Acme::EyeDrops(3pm)
๐ฆ Acme::EyeDrops(3pm) ๐ฆ
okay bestie, sit down, hydrate, because this is the manual page for Acme::EyeDrops and it is genuinely iconic. it's a Perl module that takes your perfectly normal program and gives it a glow-up so extreme that it stops looking like code and starts looking like art. we're doing Visual Programming today, periodt. ๐
โจ NAME โจ
Acme::EyeDrops - Visual Programming in Perl
๐ธ SYNOPSIS ๐ธ
use Acme::EyeDrops qw(sightly);
print sightly( { Shape => 'camel',
SourceFile => 'eyesore.pl' } );
๐ DESCRIPTION ๐
Acme::EyeDrops takes a Perl program and converts it into an equivalent Perl program, except the new one has had all those unsightly letters and numbers rinsed right out of it. no more ugly alphanumerics cluttering up your vibe. ๐
In what is, and I say this with my whole chest, a Visual Programming breakthrough, EyeDrops lets you pour the generated program into all kinds of shapes โ UML diagrams, animals, whatever โ which means you can instantly understand how a program works just by glancing at its new and improved visual representation. reading code with your eyes? over. now you read it with your soul. ๐
And here's the part that really slays: unlike Acme::Bleach and Acme::Buffy, the generated program runs without requiring that Acme::EyeDrops be installed on the target system. no cap. it's self-sufficient. it's independent. it's giving main character energy. ๐ซถ
๐ฆ EXAMPLES ๐ฆ
Getting Started
say you've got a program called helloworld.pl, and it's literally just this:
print "hello world\n";
so basic. so cute. but bestie, we can make it a camel.
to convert this little guy into an equivalent camel-shaped program, you make a file called cvt.pl that looks like this:
# cvt.pl. Convert helloworld.pl into a camel shape.
use Acme::EyeDrops qw(sightly);
print sightly( { Shape => 'camel',
SourceFile => 'helloworld.pl',
Regex => 1 } );
then you run it like this:
perl cvt.pl >new.pl
now go look at your brand new new.pl. inspect it. verify that yes, it does indeed resemble a camel. ๐ช once you've done your vibe check, run it:
perl new.pl
and confirm it behaves identically to the original helloworld.pl. same output, different aesthetic. glow-up complete. โจ
now โ instead of using the API like we just did, you might find it way 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 1 >new.pl
cat new.pl (should look like a camel)
perl new.pl (should print "hello world" as before)
and here's the tea ๐ต: the shape 'camel' is literally just the file camel.eye sitting in the EyeDrops sub-directory underneath wherever EyeDrops.pm lives. so you are free to add your own new shapes as required. go off, make a blorbo.eye. i believe in you.
for the meaning of Regex => 1 up there, go peek at 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 hand him this:
print sightly( { Shape => 'uml',
SourceFile => 'helloworld.pl',
Regex => 1 } );
and if it's 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's a Windows program and see its UML structure too, just by glancing at the code. two facts, zero reading. incredible. ๐ญโจ
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. that's it. that's the whole reason. and honestly? valid. ๐
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:
''=~(
'('."\?".
'{'.('['^'+'
).('['^"\)").(
'`'|')').('`'|
'.').('['^'/').
'"'.('`'^'#').(
'`'|'/').(('`')|
'&').('`'|'&').(
'`'|'%').("\`"|
'%').('{'^'[').
('`'|('-')).(
'['^"\.").(
'`'|"'").(
'{'^'[').('['^'(')
.('`'|'(').('`'|'!')
.('['^'/').('['^"\/").(
'`'|'%').('['^')').('['^"\(").(
'!'^'+').('`'^',').('`'|'!').('['^')').(
'['^')').('['^'"').('{'^'[').('`'^'!').('['^'+')
.('`'|'/').('`'|'#').('`'|'!').('`'|',').('['^'"').
('['^'+').('['^'/').('`'|')').("\`"| "\#").(
'!'^'+').('{'^'+').('`'|('!')).( '['
^')').('['^')').('`'|"\/").(
'['^'/').('{'^'[').('`'|'.')
.('`'|'/').('['^'/').(('{')^
'[').('`'|'!').('{'^'[').('`'
|'(').('`'|'/').('`'|('!')).(
'['^'#').('!'^'+').('!'^'+').(
'`'^'$').('`'|'%').('['^'(').(
'`'|')').('`'|"'").('`'|"\.").
','.('{'^'[').('`'|'$').("\`"|
'%').('`'|'"').('`'|'!').("\["^
'/').('`'|'%').','.('{'^('[')).(
'[' ^'(').('`'|')').('`'|'&').("\["^
'/').('!'^ '+').('{'^'+').('['^')').(('`')|
'!').('`'|'.' ).('`'|'+').('['^'(').('['^'/'). +(
'`'|'%').('['^')').('{'^'[').('{'^'+').(('`')| ( (
')'))).('`'|'%').('['^')').('['^'(').('{'^'[').( ( (
'['))^'+').('`'|'!').('['^',').('`'|'+').('['^'"'). (('{')^
'[').('['^'+').('['^')').('`'|'%').('`'|'#').(('`')| ')').('['^
'(').('!'^'+').('{'^',').('`'|'%').('`'|'%').('`'|'+').('`'|','
).('['^'"').('{'^'[').('`'|',').('`'|')').('`'|"'").('`'|'(').(
'['^'/').('{'^'[').('['^')').('`'|'%').('`'|',').('`'|')').('`'|
"\%").( "\`"| '&').('!'^'+').('!'^'+').('`'^"'").('`'|'!').(
(( '`'))|',').('`'|',').('`'|'/').('['^'+').('{'
^'[').('{'^'+').('`'|'/').('`'|'.').('`'|')'
).('`'|'%').('{'^'[').('`'|('"')).( "\`"|
'/').('`'|',').('`'|'$').'!'.('!'^'+'
).('`'^'"').('`'|'%').('`'|'%').("\["^
')').('{'^'[').('['^'/').('`'|'/').('{'
^'[').('`'|"'").('['^'.').('`'|',').('['^
'+').','.('{'^'[').('`'^'"').('['^"\.").(
'`'|'&').('`'|"\&").( '['^'"').('{'^'[').(
'`'|'!').('['^"\(").( '['^'/').('['^')').
('`'|')').('`'|'$').( '`'|'%').('!'^'+')
there's more coming, bestie โ don't go anywhere ๐
like okay bestie, this next part is literally the whole flex laid bare โ the raw, character-for-character body of it, no edits from me, no glow-up, no filter. just vibes and punctuation ๐ โจ I'm not touching a single glyph because every one of them is load-bearing, iykyk. here it is, exactly as it lives:
.('`'^'/').('['^
')').('`'|'!').('`'|'.'
).('`'|"'").('`'|'%').('{'^'['
).''. ('['
^'(' ).(
'`'| '+'
).+( ( '['
)^(( ( '"'
)))) .( ( '{'
)^(( ( ( '['
))) )) .( '['
^(( (( ( '('
))) ))). ( '['
^(( '.') ) ).(
'[' ^')' ) .+(
'[' ^(')')).( ( '`'
)|+ (( ( ((
'/' )) ) ))
).( ( ( ((
'[' ) )))^+
'.' ) .(
'`' | '.').('`'|'$').('['^'(').('!'^('+')).(
'!' ^'+').("\`"^ "\,").( ( ( "\`"))| (
'!' ) ) .+( '`' |+ ( ( (( '-' ))) )
).( ( ( '`'))|'"').( ( ( '`'))|'$').( (
'`' ) | ( ( (
(( '!' ) ) ) )) )
.( ( '{')^ ( ( (( (
(( ( ( ( ( ( (
(( ( '[' ))))))))))))))) ) ).('`'|'(').
+( ( ( ( (
( ( ( ( (
( ( ( '[' ) )
) ))) )) )
) ) )^'.').('`'|"'").('[' ^
( ( '('))).('{'^'[').(('`')| (
( ( '#')))).('`'|'!').('`'|'-' )
. ( "\`"| '%').('`'|',') .''. (
( ( '!') ) ^ '+' )
.( '{' ^'+').('['^')'). (((
( (
( (
( (
( ( (
( ( (
( ( (
( ( (
( ( ( (
( ( ( (
( '`' )) )
) ))))))))))) )
)))))))))))))|+
'%').('`'|'#').('`'|
'/').('`'|'#').('`'|')').
('`' |'/'
).+( '['^
'.') .''.
('[' ^'('
).+( '{'^
'[') .''.
('[' ^'+'
).+( '['
^'.' ).+(
'['^ '+').( '{'^
'[') .''. ( '['
^(( '+' ))).('[' ^ ')'
).( ( '`') |(( ( '/'
))) ) .('`'|'$'). ( '['
^(( ( ( '.'
))) ) ) .+(
'`' | ( '#'
)). ( ( '['
)^+ ( ( '/'
)) ) . (((
( (( ( ( ((
( (( ( ( ((
( '`') ))))))))) )))))) )|+
( ')' )). ((( '[' ))^ '-'
) .( (( ('`')))| "\%").( ((
( ( (( (( '!') )) ) )) ))^+ (( (
( ( '+' )))))).''. ( '{'^"\(").( (
( ( (( ( (
( (( ( ((
( '`' ) ))
) ))) ) )))
)))|')' ) .+(
"\["^ ( ( ( '#'
)))). ( ( ( '['
))^'/' ).('`'|'('). ('{'
^'['). ('['
^'+').( '`'|'%').('`'|'!'). ('['
^"\)").( '`'|',').('{'^'[').('`'| "'")
.(('`')| (( ','))).
('`'|"\/").( '['^')').('`'|')') .('`'|
'/').('['^ '.').('['^'(' ).''.
('!'^'+'). ('"').
'}'."\)");$:= '.'^"\~";
$~='@'|'(';$^=')'^'[';$/='`'|'.'
;$,='('^'}';$\='`'|'!';$:=(')')^
'}';$~='*'|'`';$^='+'^('_');$/=
'&'|'@';$,='['&'~';$\=','^'|';
$:='.'^'~';$~='@'|'(';$^=')'
^'[';$/='`'|'.';$,=('(')^
'}';$\='`'|'!';$:="\)"^
'}';$~='*'|('`');$^=
'+'^'_';$/=('&')|
'@';$,='['&
'~';$\=','^"\|";
$:='.'^'~'; $~=('@')|
'(';$^=')'^'[' ;$/='`'|'.'
;$,='('^"\}";$\= '`'|"\!";$:=
')'^'}';$~='*'|'`' ;$^='+'^"\_";
$/='&'|'@';$,='['&'~' ;$\=','^"\|";
$:='.'^'~';$~='@'|"\("; $^=')'^'[';$/
='`'|'.';$,='('^"\}";$\= '`'|'!';$:=')'
^'}';$~='*'|'`';$^='+'^'_' ;$/='&'|'@';$,
='['&'~';$\=','^'|';$:='.'^ '~';$~='@'|'(';
$^=')'^'[';$/=('`')| '.' ;$, ='('^'}'
;$\='`'|'!';$:=')' ^'}';$~
='*'|'`';$^=('+')^ '_';$/=
'&'|'@';$,='['&'~' ;($\)=
','^'|';$:='.'^'~'; $~='@'
|'(';$^=')'^'[';$/= "\`"|
'.';$,='('^"\}";$\= ( '`')
|'!';$:=')'^'}';$~ = '*'
|'`';$^='+'^'_';$/ = ((
'&'))|'@';$,="\["& ( ((
'~')));$\=','^'|'; ( ( ( ( ( ( (
$:)))))))='.'^"\~"; ( ( ( ( (
$~)))))='@'|'(';$^ =')'^ '[' ; (
( $/))='`'|'.';$, ='('^'}' ;($\) = (
( '`'))|'!';$: = (
')')^"\}"; ( $~)
= '*' | (
( ( (
( ( (
( ( (
( ( ( ( ( ( (
( ( ( ( (
( ( ( (
( (
( (
( ( '`')))))) )
) ) )))))))))))))
) ) )))))))) ;
( ( $^))='+'^'_';
( ( ( (
( ( ( (
( ( (
( ( ( ( (
( (
( (
( (
( ( (
( (
( ( ( (
$/)))))))
))))))))))))))
))))))))))='&'|"\@";
$,='['&'~';$\=','^'|';$:=
'.'^'~';$~=('@')| '(';$^=
')'^'[';$/='`'|'.';$, ='('^'}'
;$\='`'|'!';$:=')'^'}';$~='*'|'`';$^
='+'^'_';$/='&'|'@';$,='['&'~';$\="\,"^
'|';$:='.'^'~';$~='@'|'(';$^=')'^('[');$/=
'`'|'.';$,='('^'}';$\='`'|'!';$:=')'^'}';$~=
'*'|'`';$^='+'^'_';$/='&'|'@';$,='['&"\~";$\=
','^'|';$:='.'^'~';$~='@'|'(';$^=')'^ '['
;$/='`'|'.';$,='('^'}';$\='`'|'!';$:= ')'
^'}';$~='*'|'`';$^='+'^'_';$/='&'|'@'
;$,='['&'~';$\=','^'|';$:='.'^'~';$~=
'@'|'(';$^=')'^'[';$/='`'|'.';$,="\("^
'}';$\='`'|'!';$:=')'^'}';$~='*'|"\`";
$^='+'^'_';$/='&'|'@';$,='['&('~');$\=
','^'|';$:='.'^'~';$~='@'|'(';$^="\)"^
'[';$/='`'|'.';$,='('^'}';$\='`'|'!';
$:=')'^'}';$~='*'|'`';$^='+'^"\_";$/=
'&'|'@';$,='['&'~';$\=','^('|');$:=
'.'^'~';$~='@'|'(';$^=')'^"\[";$/=
'`'|'.';$,='('^'}';$\='`'|"\!";$:=
')'^'}';$~='*'|'`';$^='+'^('_');$/=
'&'|'@';$,='['&'~';$\=','^"\|";$:=
'.'^'~';$~='@'|'(';$^=')'^('[');$/=
'`'|'.';$,='('^'}';$\='`'|"\!";$:=
')'^'}';$~='*'|'`';$^='+'^"\_";$/= '&'
|'@';$,='['&'~';$\=','^'|';$:='.'^ (
'~');$~='@'|'(';$^=')'^('[');$/= '`'|
'.';$,='('^'}';$\='`'|('!');$:= ')'^'}'
;$~='*'|'`';$^='+'^'_';$/='&'| '@';$,='['&
'~';$\=','^'|';$:='.'^'~';$~= '@'|'(';$^=')'
^'[';$/='`'|"\.";$,= (( '('))^'}';$\='`'|
'!';$:=')'^('}');$~= ( '*')|'`';$^='+'^'_'
;$/='&'|'@';$,="\["& ( ( '~'));$\=','^'|';
$:='.'^'~';$~='@'|'(' ; $^=')'^'[';$/=
'`'|'.';$,='('^'}';$\ ='`'|"\!";
($:) =')'^'}';$~='*' |'`';$^
=(( '+'))^('_');$/= '&'
|+ '@';$,='['&"\~";
( $\)=','^"\|";$:=
'.'^'~';$~="\@"|
'(';$^=')'^"\[";
so yeah. that's the whole thing, raw, exactly like that ๐ญ๐ซถ every ^, every |, every stray backslash is doing a job and I am NOT about to mess with any of them. the way this is somehow both a picture and a program at the same time?? it's giving overachiever and I respect it ๐
ngl this is the part where most people's eyes glaze over and honestly? valid. but stay with me bestie, because the payoff is coming ๐ฅ we're not even close to done here โ keep scrolling, there's so much more ๐ธ
๐ฆ Just another Perl hacker ๐ฆ
Okay so bestie, let's get more ambitious and create a big self-printing JAPH. Like, glow-up levels of ambitious. ๐
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 โ and this is the plot twist โ 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. It's giving "we can't do this here, bestie." So 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), make sure the program to be converted is careful with its use of regular expressions and $_. No cap. ๐
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 1 -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. ๐ญ (It's giving "why is my pretty art ruining my code.")
Buffy looking in the mirror can now be created with:
sightly.pl -r 1 -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 needs two buffy2 shapes. So what do we even do?? Well bestie, you could use the "TrailingSpaces" attribute (that's the -T switch to sightly.pl) to slap the required number of trailing spaces onto each line, which lets you write a way briefer kk.pl:
open$%;chop,print+reverse.$/for<0>
and then finally produce Buffy looking in the mirror with:
sightly.pl -T -r 1 -f kk.pl -s buffy2 >bb.pl
Alternatively โจ the "Compact" attribute (the -m switch to sightly.pl) could be used to produce a solution that's completely free of any trailing spaces:
sightly.pl -m -r 1 -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)
which produces buffy.pl:
''=~('(?{'.(
'`'|'%').('['^'-'
).('`'|'!').('`'|','
).+ ( '"'
).( ( '`'
)|+ ( '/'
)). ( '['
^(( ( '+'
))) ).('`' |((
'%' ))). ( '`'
|(( '.') ) ).+
((( (( ( (((
((( ( ( (((
((( ( '\\')))
))) ) ) ) )
) )))) )))))) .'$[;' . (
( ( (( ( (
( ( ( (( ( ( (( ( ( (
( ( '`') )))) ) )
) ) ))) )
) ))) ) )
)| ( ( ( ( ((
'#' ) ) ) )))
).(('`')| ('(')).(
'`'|'/'). ('['^'+') .',(\\$'
.'=='.('[' ^'"') . '==='.+(
'`'|'#').')' . '>\\$-'
.'&&(\\$-=\\' . '$=)'.(
'`'|'&').('`' | ( '/')).(
'['^')').'\\' . '@:=<' .
('^'^(('`')| "\.")). (
'>').(';').( '!'^'+' )
.('['^'+'). ('['^')' ).('`'|
')').("\`"| "\.").( ( ('['))^
"\/").'\\$\\"'.( ( "\[")^ ( (
( ( "\#"))))). ( ( '-')) . (
( ( ('(')))).( ( ( '[')) ^ (
( '"'))).'--' . '-'. ( (
( '`'))|'#'). ( ( (
( '-')))). ( ( (
( ( '\\' ) )
) ) ) .
( ( ( (
( ( ( ( (
( ( ( ( (
( ( ( ( (
( ( ( ( (
( '$'))))))))))))))))))))))))).'-).'.('['^ ( (
( ')')))).('`'|'%').('['^'-').('`'|'%').(('[')^ (
( ')'))).('['^'(').('`'|'%').'.\\$/'.('`'|'&').( (
( '`'))|'/').('['^')').'\\@:'.('!'^'+').'"})');$:= (
( '.'))^'~';$~='@'|'(';$^=')'^'[';$/='`'|'.';$,='(' ;
This is maybe a cleaner solution ๐ though some people find the plain sightly encoding more pleasing to the eye. ngl, valid. ๐
Showing the face upside down, rather than reflected, is more easily solved with:
open$%;print+reverse<0>
and easier <em>still</em> 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 from 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. ๐ช iykyk
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're totally free to add a leading "#!/usr/bin/perl -w" line to camel.pl, so long as you <em>also</em> add a blank line after this header line. โจ (yes, the blank line is mandatory bestie, don't skip it ๐)
๐ช๐ช๐ช 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 you 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 <em>second</em> 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:
okay so here's the next round of examples and bestie they are unhinged in the best way ๐
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 ๐ฃ๏ธ
not me running this and getting pure chaos ๐ญ Run 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
and it produces:
''=~('(?{'.('`'|'%').('['^'-').('`'|'!').('`'|',').'"'.('['^',').('`'|
'!').('['^')').('`'|'.').'+(\\"'.('`'^'"').('['^')').('`'|')').(('[')^
'/' ).(
'`' |'!').('`'|')' ).(
'`' |'.').('{'^'[').('`'| ')'
).( '['^'(').('{'^'[').('`'|'.' ).(
'`' |'/').('['^'/').('{'^'[').("\["^ ','
).( '`'|'/').('['^')').('['^'/').("\`"| '('
).( '{'^'[').('`'|'!').('`'|'.').('{'^'['). (((
'`' ))|'/').('`'|',').('`'|'$').("\{"^ '[' ).(
'[' ^'(').('`'|'(').('`'|'/').('`'|'%') .(( '!'
)). '\\",\\"'.('{'^'/').('`'|'(').("\`"| '%' ).(
'[' ^')').('`'|'%').('{'^'[').('`'|"\!").( '['^ ')'
).( '`'|'%').('{'^'[').('`'|'.').('`'|'/').( "\{"^ '['
).( '`'^'!').('`'|'-').('`'|'%').('['^"\)").( ('`')| ')'
).( '`'|'#').('`'|'!').('`'|'.').('{'^'[').('`'| ')').('`' |((
'.' ))).('`'|'&').('`'| ')').('`'|'$').('`'| '%'
).( '`'|',').(('[')^ '(').('{'^'['). (((
'`' ))|')').("\`"| '.').(('{')^ '['
).( '`'^('"')).( '`'|'!'). (((
'`' ))|("'")).( ('`')| '('
).( '`'|"\$").( "\`"| '!'
).( '`'|"\$"). ('!\\",\\"').( '{'^',').("\`"| '%') .+(
'{' ^('[')).( ( '`')|'(' ) .('`' |((
'!' ))).('['^'-' ) . ( ( '`')|'%').('{'^ '['
).( '['^'/') . ( ( ( '`'))| '('
).( '`'|'%') . +( ( ( ( '`'))) |((
'-' ))).('{' ^ ( ( ( '['))) ).(
'[' ^'(').( '['^'.').('[' ^')').('['^')'). +( (( '`'
))| '/'). ( ( ( '['
))^ ( ( ( ( ( '.'
))) ) ) ) . (((
'`' ) ) | ( '.'
)). ( ( ( ( ( '`'
))) ) |+ '$'). +( ( '`'
)|+ ( ( ( '%'
))) ) . (((
'`' ) ) | '$'
).( ( ( ( '{'
))) ^'[').('`' | ( ( ')'
))) . ('`'|'.').('{' ^ '['
).( ( '[') ^'/' ) . ( '`'
|(( ( ( (( ( ( '('
))) ) )) )))
.+( ( (( '`' ) ))|
'%' ).('`'|')').( ( '['
)^+ ( ')')).('{'^ ( '['
)). ( '['
^(( ( ( '/'
))) ) ).(
'`' | '!'
).( ( ( '`'
))| ( ( '.'
))) . ( '`'
|(( ( ( '+'
))) )).('['^'(' ).+
'!' .((
'\\')).'",\\"'.('`'^')').('{'^'[').('['^'(').('['^'+').('`'|'%').('`'|
'!').('`'|'+').('{'^'[').('`'|'"').('`'|'%').('['^'/').('['^'/').('`'|
'%').('['^')').('{'^'[').('`'^'%').('`'|'.').('`'|"'").('`'|',').('`'|
')').('['^'(').('`'|'(').('{'^'[').('['^'/').('`'|'(').('`'|'!').('`'|
'.').('{'^'[').('['^'/').('`'|'(').('`'|')').('['^'(').('{'^'[').('['^
'-').('`'|')').('`'|',').('`'|',').('`'|'!').('`'|')').('`'|'.').('{'^
'[').('`'^'"').('['^'.').('['^'(').('`'|'(').'!\\")['.('['^')').("\`"|
'!').('`'|'.').('`'|'$').'('.('^'^('`'|'*')).')],\\$/"})');$:='.'^'~';
๐บ 99 Bottles of Beer ๐บ
okay this one is a whole saga ๐ฆ 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. ๐ฆโจ
So like, 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/^ /
There's this interesting obfuscated Sierpinski triangle generator that's giving major main character energy:
#!/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, bestie, 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
and it's producing:
''=~('(?{'.('`'|'%').('['^'-').('`'|'!').('`'|"\,").'"\\$-=!\\$%<<('.(
'['^'+').('`'|'/').('['^'+').'||'.('^'^('`'|'*')).');'.('['^'+').('['^
(( ((
(( (( ((
(( ')') ))
)) )) )) ))
)) .(('`')| ((
(( (( (( ((
(( ')') )))) ))
)) )) )) .( (( ((
(( '`'))))))|'.').( ((
(( (( (( ((
(( '[') )))) ))
)) )) )^ (( (( ((
(( '/'))))) )))).''. ((
(( (( (( (( (( ((
(( '\\' )))) )))) )))) ))
)) .+ (( (( (( (( (( (( (( ((
(( '$')))))))))))))))))).'\\"'.('[' ^+
(( (( (( ((
(( '#') )))) ))
)) )) .+ (( (( ((
(( '\\')))) )))).'$' .+
(( (( (( (( (( ((
(( '-') )))) )))) )))) ).
(( (( (( (( (( (( (( (( (( ((
(( ','))))))))))))) ))))))))).("\`"| ((
(( (( (( (( (( ((
(( '-') )))) )))) )))) ))
)) .( (( (( (( (( (( (( (( ((
(( '`'))))) )))))))) )))))|(( '!'))).( ((
(( (( (( (( (( (( (( (( (( ((
(( '[') )))) )))) )))) )))) )))) )))^ '+') .+
(( (( (( (( (( (( (( (( (( (( (( (( (( (( (( (( (( ((
(( '(')))))))))))))))))))))))))))))))))))))).'\\$-&\\$_?'."'".('{'^ ((
(( ((
'['))))))).('{'^'[')."'".':'."'".'/\\\\\\\\'."'".',\\$%..\\$.++),\\$/'
.('['^',').('`'|'(').('`'|')').('`'|',').('`'|'%').'\\$---"})');$:='.'
Dueling Dingos ๐๐
Okay so 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, bestie:
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 is 2577 lines long, so it 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
and it's producing:
''=~('('.'?'.'{'.(
'['^'+').('['^')').('`'|
')').('`'|'.').('['^'/').'"'
.('`'^'-').('['^'"').('{'^'[').(
'`'|'(').('`'|'%').('`'|'!').("\`"|
'$').('{'^'[').('`'|')').('['^('(')).(
'{'^'[').('`'|'(').('['^'.').('['^"\)").(
'['^'/').('`'|')').('`'|'.').('`'|"'").','.
('{'^'[').('`'|'-').('['^'"').('{'^'[').('['^
')').('`'|')').('`'|"'").('`'|'(').('['^'/').(
'{'^'[').('`'|'%').('['^'"').('`'|'%').('{'^'['
).('`'|'&').('`'|'%').('`'|'%').('`'|',').(('[')^
'(').('{'^'[').('`'|',').('`'|')').('`'|'+').("\`"|
'%').('{'^'[').('`'|')'). ('['^ ('/')).
"'".('['^'(').('{'^'['). ("\`"|
"'").('`'|'/').('`'|')' ).''.
('`'|'.').('`'|"'").('{' ^'[')
.('[' ^'/').('`'|'/').(('{')^ '[').
('['^'+' ).('`'|'/').('['^'+'). ('!'^
'+').('`'| ','). ('`'|')').('`' |'+')
.('`'|'%') .''. ('{'^"\[").( "\`"|
'!').('{'^ ( "\[")).( "\`"|
'-').('`'| ( '/')).( "\["^
'(').('['^ ( '*' )).
('['^'.' ) .+( ( ( ( ( ( (
'`')))) ) )| ( ( (
')'))) ) . ( (
"\[")^ ( (
'/'))) . ("\`"| '/'). (
('{')^ '[' ).('`' |'$') .
("\["^ ( ( (
')'))) ) . (
('`')| ( ')')) . (
('`')| ( '.')) . (
('`')| ( ( (
'+')))) . +( ( (
('`')))| ( (( ( (
')')))))). ( (( ( (
'`'))))|'.'). ( (( ( (
'`'))))|"'").('{'^('[')).( (( (
'`')))|'&').('['^')').("\`"| (( (
'/')))).('`'|'-').('{'^'[').( '`'|
'!').('`'|'.').('{'^'[').("\`"| (
'%')).('['^'#').('['^'+').("\["^ (
')')).('`'|'%').('['^'(').('[' ^'(').(
'`'|'/').('{'^'[').('`'|'!').
('`'|'$').('`'|'$').('`'|')'
).('`'|'#').('['
^ '/').('{'^'[').(('[')^ (
( ','))).('`'|')').('['^'/') .
( '`'|'(').('{'^'[').('`'|'(').( (
( '`'))|')').('`'|"'").('`'|'(').( (
( '!'))^'+').('`'|'"').('`'|(',')).( (
( '`'))|'/').('`'|'/').('`'|('$')).( (
( '{'))^'[').('['^'+').('['^')').('`'| (
( '%'))).('['^'(').('['^'(').('['^'.') .
( '['^')').('`'|'%').','.('{'^('[')).( (
( '`'))^')').('{'^'[').('['^',').('`'| (
( '!'))).('`'|'.').('['^'/').('{'^'[') .
( '['^'/').('`'|'/').('{'^'[').('`'| (
( '#'))).('['^')').('`'|'!').(('[')^ (
( ','))).('`'|',').('{'^'[').('['^ (
( '('))).('`'|'/').('`'|('-')).( (
( '`'))|'%').('['^',').('`'| (
( '('))).('`'|'%').('['^ (
')')).('`'|'%').
+( ((
'{')) ^ (
"\[")).( ( (
'`'))|'$' ) . ( (
'`')|'!').( ( ( ( (
'`'))))|'-') . ( ( (
'['))^'+').( ( ( ( (
'{'))))^'[') . ( ( (
'`'))|'!').( ( ( ( (
'`'))))|'.' ) . ( (
'`')|'$' ).('{'^'[' ) . ( (
'`')|'$').('`'| ('!')).( '['^ ')' ) .
('`'|'+').('{'^'[') .('`'|'!').('`'| (
'.')).('`'|'$').('!'^'+').('['^"\*").( (
'[')^'.').('`'|')').('`'|'%').('['^'/'
).('{'^'[').('`'|'!') .('`'|'.').
('`'|('$')).( '{'^('[')).(
'`'^')'
).( '{'
^+ ( ( (
(( ( ( (
(( ( ( (
(( ( ( (
(( ( ( (
'[') ) ) )
)) ) ) ) )
) ) ) )
) ) ) )
) ) ) )
) ) . (
( ( ( (
( ( ( (
( ( ( (
( ( ( (
'`'))))
))))))
)))))
)|'#'
).''.
('`'|
'/').('`'|'.').('['^'(').('`'|')').(('`')| '$').(
'`'|'%').('['^')').('{'^'[').('`'|('.')).( '`'|'%').
('['^'-').('`'|'%').('['^')').('{'^'[').('['^ '/'
).('`'|'/').('{'^'[').('['^'/').('`'|'/').( '['
^'.').('`'|'#').('`'|'(').('{'^'[').("\`"| '!'
).('{'^'[').('`'|'+').('`'|'%').('['^'"' ).(
'`'|'"').('`'|'/').('`'|'!').('['^')').( '`'|
'$').('{'^'[').('`'|'!').('`'|("'")).( '`'|
'!').('`'|')').('`'|'.').'.'.(('!')^ '+')
.'"'.'}'.')');$:='.'^'~';$~='@'|'(';$^=
')'^'[';$/='`'|'.';$,='('^'}';$\='`'
|'!';$:=')'^'}';$~='*'|'`';$^=
'+'^'_';$/='&'|('@');$,=
'['&'~';$\=','^'|'
โจ Error Handling โจ
Okay bestie, real talk about errors: the sightly function returns a properly shaped program string, and that is it โ there is no error return. Like, none at all. If something is badly wrong, sightly calls die. So if you're calling sightly in an environment where it is not acceptable to die, please please please 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" }
โ ๏ธ no error return, onlydie. Wrap it inevalif dying is not the vibe. ๐ซถ
๐ช 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. And ngl, even 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. ๐๐
and here she is, bestie. the shape. the whole shape. pure Perl, no cap ๐
''=~('(?' .'{'.('['
^+ (( (( ((
(( (( (( ((
(( (( ( ((
(( (( (( ((
(( (( (( ((
(( (( (( (
(( (( (( ((
(( (( ( (
(( ( (( ((
( (( (( ((
( (( (( ((
( ( (( ((
( (( (( ((
(( ( (( (
(( (( ( ((
(( (( (( '+'
)))) ) )) ))))
))))) )) )) ))))))
))))))) )) )) )))))))
))))))))) )) )) )))))))))
))))))))))))) )))))))))))))
))))))))))))) ))))))).("\["^
')').('`'|')'). ('`'|'.').("\["^
'/').'"'.('`'^'"'). ('`'|',').('`'|'!'
).('`'|'#').('`'|'+') .('{'^'[').('{'^'-').(
'`'|')').('`'|'#').("\["^ '/').('`'|'/').('['^')').(
'`'|')').('`'|'!')."'".('[' ^'(').('{'^'[').('['^('(')).(
'`'|'%').('`'|'#').('['^')').('`'|'%').('['^'/').('{'^'[').
('`'|'"').('['^')').('`'|'!').('{'^'[').('`'|'$').(('`')|
'/').('`'|'.').('`'|'!').('['^'/').('`'|'%').('`'|'$').
('{'^'[').('`'|"\"").( '['^'"').('{'^"\[").(
'`'^'(').(('`')^ '&').('`'^'"').
('!'^'+') .('"})'))
The bra, donated by Elaine -HFB- Ashton, was bought by the artist expressly for this artwork at the YAPC::Europe 2003 auction.
the artist bought a literal bra at a Perl conference auction to make it into Perl art. we have no choice but to stan. ๐
An interpretation of Brocard's modern masterpiece is given below:
Victoria Bra, Secret Tango (2003) L. Brocard 1976- This one is the third work in Brocard's acclaimed "Naranja" sequence, and it absolutely goes off on the theme of semantic [a]chromatic aspects of aranciata visual perception, which he first explored in his celebrated "Buffy" series โ and it fully explores the concept of supporting relationships, which he'd only touched on in his earlier works. The site's central artifact is a stark reminder of the lack of support in contemporary relationships, and the jumbled juxtaposition of its two cups โ literally giving "discarded in a hurry" โ symbolizes the excessive rapidity and tautness of modern life. And as always with Brocard, it is vital to consider the intertextuality of the title of the work, so you can 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"? In the context of the universe that is the present work, is it 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. โ ๏ธ
okay but the way "tango" rhymes with "mango" is genuinely the whole thesis here and the art world just wasn't ready. iykyk ๐ฅญ๐
๐ Love Birds ๐
My Dark Tunnels teammate Taffy is devoted to โ and firmly believes in โ a love calculator web site where you type in two names and it reports your love compatibility.
so obviously we calculated the love compatibility of our entire team, and it came out disappointingly low, with one notable exception. Taffy and Muss recorded an astonishingly high love compatibility of ninety nine percent โ the highest ever recorded! ๐ญ๐
As a tribute to their affectionate and touching bromance, I wrote this program:
use Acme::EyeDrops qw(sightly get_eye_string hjoin_shapes);
print sightly( { ShapeString => hjoin_shapes(3, (get_eye_string('heart2'))x2),
SourceString => "Muss and Taffy have 99% Love Compatibility\n",
Regex => 1,
Print => 1 } );
to generate:
''=~( "\(". "\?". '{'.(
'['^'+'). ('['^')') .('`'|')' ).(('`')|
'.').('['^'/' ).'"'.(('`')^ '-').('['^'.' ).('['^'(').(
'['^'(').("\{"^ '[').('`'|'!'). ('`'|'.').('`'| '$').('{'^'[').
('{'^'/').('`'|'!').('`'|'&').( '`'|'&').('['^'"').('{'^"\[").(
'`'|'(').('`'|'!').('['^'-'). ('`'|'%').('{'^'[').(';'&'=')
.(';'&'=').'%'.('{'^"\[").( '`'^',').('`'|'/').('['^'-'
).('`'|'%').('{'^('[')).( '`'^'#').('`'|'/').("\`"|
'-').('['^'+').('`'|'!' ).('['^'/').('`'|')').(
'`'|'"').('`'|')'). ('`'|',').('`'|')')
.('['^'/').('[' ^'"').('!'^'+')
.'"'.('}'). ')');$:='.'
^'~';$~ =('@')|
"\("; ;")";
;#; ;#;
; ;
By the way, this is the same heart shape that Perl Monk Falkkin used to successfully propose to his girlfriend Kristen in August 2004.
not the Perl Monk proposal lore ๐ญ๐ obsessed with them fr fr
๐ฆ 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:
''=~('('.'?'.'{'.('`'|('%')).(
'['^"\-").( '`'|'!').('`'|','
).'"'.('[' ^'+').('['^')').(
'`'|')'). ('`'|'.').('['^'/'
).("\{"^ '[').'\\'.'"'.('`'|
"\(").( (( '`'))|'%').('`'|
',') .( '`'|',').("\`"|
'/' ).( '{'^'[').("\["^
(( ',') )).('`'|"\/").(
( (( '[')))^')').(
(( ( '`')))|',').(
'`' | '$').'\\'.''.
'\\' .('`'|"\.").
'\\'. (( '"'))."\;".(
'!'^"\+"). '"'.'}'.')')
;$:=('.')^ '~';$~="\@"|
'(';$^=')' ^'[';$/='`'|
('.');$,= '('^'}';$\=
'`'|'!'; $:=')'^'}'
;$~='*' |"\`";$^=
'+' ^+ ( '_');$/=
'&'| '@'; $,='['&
'~'; $\=',' ^"\|";
($:)= ('.')^ "\~";
$~='@'| "\("; ($^)
=')'^'[';$/ =('`')| '.'
;$,='('^'}' ;$\=('`')| (
'!');$:=')' ^'}';$~='*'| ((
'`'));$^='+'^'_';$/='&'|'@';#;
Buffy rotating, Buffy on a pony, and a reduced inverted cricket โ she contains multitudes, honestly. ๐
โ๏ธ 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. iykyk ๐ซถ
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 ๐
okay bestie, this is the whole function menu, no skips, no cap ๐ซถ
๐
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 theget_eye_dir()directory unless overridden by theEyeDirattribute) 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โ Regex can take the following values:0: do not embed source program in a regex- If Regex is positive, embed the program in a regex and:
1: add a leading"use re 'eval';"for Perl 5.18+ only2: do not add a leading"use re 'eval';"3: add a leading"use re 'eval';"
- 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 overrideBorderGapwith one or more from the above.BorderWidthโ Put a border around the shape. Width of border.BorderWidthLeft,BorderWidthRight,BorderWidthTop,BorderWidthBottomโ bestie, you can overrideBorderWidthwith one or more of these four. Mix and match, go off ๐Widthโ lowkey ignored for.eyefile shapes, ok? For the built-in shapes it gets interpreted appropriately for whatever shape you picked, typically as the shape width in characters. And if you didn't specify any shape at all? You get a rectangular block ofWidthcharacters. Boom. ๐EyeDirโ normally.eyefiles get pulled from theEyeDropsdirectory underneath whereverEyeDrops.pmis living. You can override that by handing it a directory that contains your.eyeshape files. Custom shapes era ๐InformHandlerโ by default,sightlyprints status of what it's doing toSTDERR. You can override this by giving it a subroutine reference that takes a single inform string argument. Want it to just shut up? Set it tosub {}. Iconic. ๐คซTrapEvalDieโ Boolean. Adds a closingdie $@ if $@to the generated program. Here's the tea: when anevalcode block calls thediefunction, the program doesn't die โ instead the die string is returned toevalin$@. Using this flag lets you convert programs that calldie. ๐ชคTrapWarnโ Boolean. Adds a leadinglocal $SIG{__WARN__}=sub{};to the generated program. This shuts up some warnings. Use this option if your generated program emits'No such signal: SIGHUP at ...'when run with warnings enabled. No more noise ๐งFillerVarโ a reference to a list of 'filler variables'. A filler variable is a Perl variable made of exactly two characters:$and a punctuation character. Like, for example,FillerVar => [ '$:', '$^' ]. Do not use$;or$"or$_as filler variables. Alternatively, you may set this to''if you don't want any filler at all, 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 โจ
Okay so when you specify a shape like this:
sightly( { Shape => 'fred' ...
first a built-in "fred" shape is looked for, and then EyeDrops goes looking for the file fred.eye in the get_eye_dir directory. But if you put a / or a . in the Shape attribute, it looks for a file with that name instead, like:
sightly( { Shape => '/tmp/fred.eye' ...
And finally โ plot twist โ you can specify a shape with a string, like:
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' } );
you get a shapeless sightly string with no spaces or newlines. Want to break that string into fixed width lines? Use the Width attribute:
print sightly( { SourceFile => 'helloworld.pl',
Width => 40 } );
Generally you should specify the Width attribute of built-in shapes. And heads up โ 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 inBannerStringattributesrcbannerโ Linux banner command (/usr/games/banner -w Width) of source textsiertriโ A Sierpinski triangle (2**Widthlines)triangleโ A triangle (widthWidthcharacters)allโ A shape consisting of all.eyeshapes joined together (Widthblank 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 twangedadrianhโ Perl qa expertalienโ 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 llamaautrijusโ The father of Pugsbaghdadโ Baghdad Bob aka Comical Alibeerโ Beer glass designed by Matthew Byng-Maddick for the cam.pm Beerfestival Perl Programming Contest 2002bighornโ Ovis canadensis (bighorn sheep) found in the Rocky Mountainsbleachโ Vertical banner of "use Acme::Bleach;"bottleโ A bottle of beerbottle2โ Abbreviated version of shape bottlebottle3โ A bottle of champagne with a champagne glassbraโ A brabuffyโ Vertical banner of "Buffy"buffy2โ Buffy's angelic facebuffy3โ Buffy riding a ponybuffy4โ 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 zoocampmโ Horizontal banner of "cam.pm"candleโ A Christmas candlechina1โ 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 coffeecricketโ Australia are world champions in this gamedamianโ The Acme namespace is all his faultdanโ The father of parrotdebianโ 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, Hollandeyeโ An eyeflag_canadaโ Canada's flag, contributed by`/anickgellyโ Featured speaker at every session of Y::E 2003, Parisgolferโ A golfer hitting a one ironhalloweenโ A witch riding a broomstickheartโ A heart shape contributed by`/anickheart2โ A heart shape modelled on one by Falkkinhipowlsโ A pair of hip owlsjaphโ JAPHs were invented by Randal L Schwartz in 1988jonโ Kick-started the Perl 6 development effort by smashing a standard-issue white coffee mug against a hotel walljon_oxerโ Linux Australia bigwig (contributed by Paul Fenwick)kangarooโ A kangarookansai_pmโ Kansai.pm's mascot (Tiger with Perl characters) contributed by Takanori KAWAI (Japanese)kermitโ Kermit the frogkoaladileโ A cross between a koala and a crocodilelarryโ Wall, Larry (as opposed to Russell Wall who is Wall, Russ)larry2โ Caricature of Larry contributed by Ryan Kingllamaโ 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 Australiamap_italyโ Map of Italymap_japanโ Map of Japanmap_ukโ Map of United Kingdom and Irelandmap_world1โ World globe, Asian viewmap_world2โ World globe, African viewmap_world3โ World globe, American viewmerlynโ Just another Perl hacker, aka Randal L Schwartzmongersโ Perl Mongers logomooseโ A moosemoosecamelโ A moose and a camel (modelled after http://irclog.perlgeek.de)mosquitoโ A mosquitomusicโ A musical symbolnawโ Naked Arm Wrestling (Y::E 2002, Munich)operaโ Opera browser logo (contributed by Cosimo)pandaโ A panda designed by Yanni Ellen Liuparrotโ Originally an April fool's joke, the joke was that it was not a jokepgolfโ Perl Golf logo (inspired by`/anick)ponyโ Horizontal banner of "Pony"pony2โ Picture of a Ponypugsโ Horizontal banner of "Pugs"pugs2โ Picture of a Pugs dogridingโ Horizontal banner of "riding"roseโ A rosesantaโ Santa Claus playing golfsanta2โ Santa Claus carrying presentssaturnโ The planet Saturnschwernโ is my bitchschwern2โ Shape schwern without the bannersimonโ The inventor of parrotsmileyโ A smiley facesmiley2โ Pulling a facesmiley3โ A sad facesmiley4โ Another sad facesnowโ Snowflake designed by Matthew Byng-Maddick for the cam.pm Christmas Perl Programming Contest 2002spiderโ A spider (tarantula)spoonโ A wooden spoonthumbsupโ A thumbs up shape modelled on one by Jiuntonickโ Pictorial representation of a golf contest between Ton Hospel and`/anick; colourful but not very suspensefultprโ Vertical banner of "The Perl Review"umlโ A UML diagramundiesโ A pair of underpantswindowโ A windowwriting_perlโ Perl in camel-style by Takanori KAWAI (Japanese)yanickโ Caricature of`/anick's nogginyanick2โ Uttered by`/anickduring TPR02yanick3โ Pictorial version of yanick2yanick4โ Abbreviated version of shape yanick
It is easy to create your own shapes, bestie, for real. For some ideas on shapes, point your search engine at Ascii Art or Clip Art. And if you generate some nice shapes, please send them in so they can be included in future versions of EyeDrops. Your art could be canon ๐๐ซถ
๐ธ Shape Properties ๐ธ
All the .eye shape files have a corresponding .eyp shape property file, specifying the shape's properties. Cute, right? A whole little sidecar situation ๐
Currently, the allowed shape properties are:
namenickdescriptioncpanidauthorauthorcpanidsourcekeywords
where valid keywords are:
facepersonperlhackeranimalobjectplanetmapflagsportunderwearhbannervbannerlogodebianopera
Wanna see how shape properties actually get used in the wild? Say you want every single shape that's just the lil face of a perl hacker. Bestie, it's literally this:
use Acme::EyeDrops qw(find_eye_shapes);
my @perlhackers = find_eye_shapes('face',
'person',
'perlhacker');
Heads up though: there's a secret implicit AND between every keyword, no cap. So that code up there? It's finding all shapes that are face AND person AND perlhacker. All three, every time.
And you can drop an OR into any argument too, like:
my @perlhackers = find_eye_shapes('face',
'person OR animal',
'perlhacker');
which finds everything matching face AND (person OR animal) AND perlhacker. The vibes are math and the math is vibing. โจ
Don't wanna mess with the API at all? Totally valid. There's a findshapes.pl command chillin' in the demo directory:
findshapes.pl -h (for help)
findshapes.pl -v face person perlhacker
That last one shows you the faces and the properties of literally every perl hacker shape. Gorgeous.
โ ๏ธ Okay important lil disclaimer bestie: these shape properties are experimental and might change in future A::E releases. Don't build your whole personality on them. ๐
๐ BUGS ๐ (the messy parts, we love her anyway)
A truly diabolical shape โ like one with a ton of single character lines โ will absolutely defeat the shape-pouring algorithm. It's giving chaos and the algorithm is not surviving it. ๐
You can eliminate all alphanumerics (via Regex => 1) only if the program you're converting is careful with how it uses regular expressions and $_. If you need to convert complex programs, you must use Regex => 0, which emits a leading unsightly double eval. Yes, it's ugly. Yes, it's necessary. We cope.
The code generated by a non-zero Regex needs Perl 5.005 or higher to actually run. Run it on anything earlier and you'll likely see this error message: "Sequence (?{...) not recognized".
If you're on Perl 5.18+, the generated file needs a leading use re 'eval' whenever a positive value for Regex is used. Don't skip it, it will not be cute.
The converted program runs inside an eval, which can cause problems for non-trivial programs. A die statement or an INIT block, for instance, may cause trouble. If you're desperate, give the TrapEvalDie and TrapWarn attributes a go and see if they fix the problem.
If the program you're converting uses the Perl format variables $:, $~ or $^, you may need to explicitly set the FillerVar attribute to a Perl variable/s that the program isn't using.
Linux /usr/games/banner does not support the following characters:
\ [ ] { } < > ^ _ | ~
And when the CPAN Text::Banner module gets enhanced, it'll be used instead of the Linux banner command. Future glow-up pending. ๐ธ
๐ AUTHOR ๐
Andrew Savige <asavige@cpan.org>
๐ SEE ALSO ๐ (the link dump, we stan a citation queen)
Acme::EyeDropslightning talk by Flavio Poletti at YAPC::Europe 2008 athttp://yapc.tv/.Acme::EyeDropsin JPerl Advent Calendar (Japanese) athttp://perl-users.jp/articles/advent-calendar/2009/casual/08.html.- The history of
Acme::Bleach,Acme::EyeDropsand related modules athttp://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. (iconic, honestly) - Japanese translations of selected CPAN modules (including
Acme::EyeDrops) can be found athttp://perldoc.jp/docs/modules/. (Japanized Perl Resources Project is athttps://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/andhttp://archive.develooper.com/fwp@perl.org/msg03193.html. Similar sites exist for hello world programshttp://www2.latech.edu/~acm/HelloWorld.shtml, and quineshttp://www.nyx.net/~gthompso/quine.htm. - To learn more about HQ9+ programming visit
http://www.cliff.biffle.org/esoterica/hq9plus.htmlandhttp://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=384100(Propose.),http://www.perlmonks.org/index.pl?node_id=397958(Saturn). - Changes to Perl 5.18 regex behavior are discussed at
http://perlmonks.org/?node_id=1030569. - 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 athttp://codegolf.com/. Ton Hospel's excellent generic golf tester can be got fromhttp://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::BleachAcme::SmirchAcme::BuffyAcme::PonyAcme::ChuckNorrisAcme::AsciiArt2HtmlTableAcme::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.
The "Love Birds" section was provoked by Muss, Jiun and Taffy. The thumbsup shape was derived from one originally designed by Jiun.
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. (main character energy, truly)
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-2015 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.
and that's the whole page bestie!! ๐
โจ This gorgeous lil artifact is Acme::EyeDrops(3pm), living under perl v5.36.0, dated 2022-11-19 โ so if you see that version and date floatin' around, that's your girl. Now go forth and obfuscate something beautiful. ๐ฆ๐๐
๐ฆ where this page comes from
- debian bookworm: libacme-eyedrops-perl 1.62-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libacme-eyedrops-perl 1.62-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libacme-eyedrops-perl 1.62-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libacme-eyedrops-perl 1.62-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libacme-eyedrops-perl 1.62-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms