=encoding euc-jp =head1 名前 Acme::EyeDrops - Perlにおけるビジュアル・プログラミング(Visual Programming) =head1 概要 use Acme::EyeDrops qw(sightly); print sightly( { Shape => 'camel', SourceFile => 'eyesore.pl' } ); =head1 説明 Cは、同等の、それでいて見苦しい文字や数字が一切ない ものに変換します。 ビジュアル・プログラミング(Visual Programming)によるブレークスルーにおいて、 EyeDropsにより作成されたプログラムをUMLダイアグラムのような様々な形に 吐き出させることにより、その新しく改良された視覚的表現を一目見るだけで、 そのプログラムがどのように機能するかをすぐに理解できるようにします。 Cには似ていますが、C や Cとは 違い、生成されたプログラムはターゲット・システムにCを インストールすることを必要としないで走ります。 =head1 利用例 以下のようなコードが入っている、Fというプログラムを 持っているとします: print "hello world\n"; 以下のようにすることで、このプログラムをラクダに見えるようにすることが できます: print sightly( { Shape => 'camel', SourceFile => 'helloworld.pl', Regex => 1 } ); 上記のAPIを使う代わりに、FディレクトリにあるFコマンドを 使うほうが便利だと思うかもしれません: sightly.pl -h (ヘルプ) sightly.pl -s camel -f helloworld.pl -r >new.pl cat new.pl (ラクダのようにみえるはず) perl new.pl (前と同じように"hello world"と出力) C<'camel'>という形は、Fと同じディレクトリにある ファイルFであるということに注意してください。そのため 必要に合わせて、あなた独自の形を追加することもできます。 =head2 あなたのプログラムをわかりやすくする あなたの上司があなたのプログラムを説明するUML図を指示したならば、 彼に、これを提出することが出来ます: print sightly( { Shape => 'uml', SourceFile => 'helloworld.pl', Regex => 1 } ); もし、それがWindowsプログラムであれば、図形を組み合わせる ことにより、それも示すことができます: print sightly( { Shape => 'uml,window', Gap => 1, SourceFile => 'helloworld.pl', Regex => 1 } ); これは改造された視覚的表現を生成します: ''=~('('.'?'.'{'.('`'|'%').('['^'-').( ( ( ( ( ( ( ( ( ( ( '`'))))))))))|'!').('`'|',').'"'.('['^ ( ( ( ( ( '+')))) ) ) .('['^')').('`'|')').('`'|'.').(('[')^ ( ( ( ( '/'))))).('{'^'[').'\\'.('"').( '`'|'(').('`'|'%').('`'|"\,").( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( '`'))))))))))))))))))))|"\,").( '`'|'/').('{'^'[').('['^"\,").( '`'|'/').('['^')').('`'|',').('`'|'$').'\\'.'\\' .('`'|'.').'\\'.'"'.';'.('!'^'+').'"'.'}'."\)"); $:='.'^'~';$~='@'|'(';$^=')'^'[';$/='`'|"\.";$_= "\("^ (( '}')) ;($,) =( '`')| "\!"; $\ =')'^ "\}"; $: ='.'^ "\~"; $~ ='@'| "\("; $^ =')'^ "\["; $/ ='`'| "\."; $_ ='('^ "\}"; $, ='`'| "\!"; $\ =')'^ "\}"; $: ='.'^ '~';$~='@'|'(';$^=')'^'[';$/='`'|'.';$_='('^'}'; ($,)= (( '`')) |'!'; $\ =')'^ "\}"; $: ='.'^ "\~"; $~ ='@'| "\("; $^ =')'^ "\["; $/ ='`'| "\."; $_ ='('^ "\}"; $, ='`'| "\!"; $\ =')'^ "\}"; $: ='.'^ "\~"; $~ ='@'| '(';$^=')'^'[';$/='`'|'.';$_='('^'}';$,='`'|'!'; $\=')'^'}';$:='.'^'~';$~='@'|'(';$^=')'^"\[";$/= '`'|'.';$_='('^'}';$,='`'|'!';$\=')'^'}';$:='.'; コードを一目見ただけで、それがWindowsプログラムであることが わかり、そのUML構造も見ることが出来る、これがビジュアル・ プログラミングによるブレークスルーなのです。 Linuxにのみ、そのFコマンドを プログラムのソーステキストに適用することができます: print sightly( { Shape => 'srcbanner', Width => 70, SourceFile => 'helloworld.pl', Regex => 1 } ); その文字が大きく、読みやすくなるので、生成されたプログラムは 元のものよりも理解しやすくなります。 =head2 簡略化されたPerl6の歴史 これはこれまでのPerl6開発作業の概要です: print sightly( { Shape => 'jon,larry,damian,simon,parrot', Gap => 3, Regex => 1, Print => 1, SourceString => <<'END_HAIKU' } ); Coffee mug shatters Larry Apocalyptic Parrot not a hoax END_HAIKU 生成されるもの: ''=~( '('."\?". '{'.('['^'+' ).('['^"\)").( '`'|')').('`'| '.').('['^'/'). '"'.('`'^'#').( '`'|'/').(('`')| '&').('`'|'&').( '`'|'%').("\`"| '%').('{'^'['). ('`'|('-')).( '['^"\.").( '`'|"'").( '{'^'[').('['^'(') .('`'|'(').('`'|'!') .('['^'/').('['^"\/").( '`'|'%').('['^')').('['^"\(").( '!'^'+').('`'^',').('`'|'!').('['^')').( '['^')').('['^'"').('{'^'[').('`'^'!').('['^'+') .('`'|'/').('`'|'#').('`'|'!').('`'|',').('['^'"'). ('['^'+').('['^'/').('`'|')').("\`"| "\#").( '!'^'+').('{'^'+').('`'|('!')).( '[' ^')').('['^')').('`'|"\/").( '['^'/').('{'^'[').('`'|'.') .('`'|'/').('['^'/').(('{')^ '[').('`'|'!').('{'^'[').('`' |'(').('`'|'/').('`'|('!')).( '['^'#').('!'^'+').'"'.'}'.')' );$:='.'^'~';$~='@'|'(';$^=')' ^'[';$/='`'|'.';$_='('^'}';$,= '`'|'!';$\=')'^'}';$:='.'^'~'; $~='@'|'(';$^=')'^'[';$/=('`')| '.';$_='('^'}';$,='`'|'!';$\=')' ^(( '}'));$:='.'^'~';$~='@'|"\(";$^= ')'^'[';$/ ='`'|'.';$_='('^'}';$,='`'|"\!"; $\=')'^'}';$: ='.'^'~';$~='@'|'(';$^=')'^"\["; $/ ='`'|'.';$_='('^'}';$,='`'|'!';$\=')'^"\}";$:= ( ( '.'))^'~';$~='@'|'(';$^=')'^'[';$/='`'|('.');$_= ( ( '('))^'}';$,='`'|'!';$\=')'^'}';$:='.'^'~';$~="\@"| '(';$^= ')'^'[';$/='`'|'.';$_='('^'}';$,='`'|'!';$\=')'^'}'; $:='.'^'~' ;$~='@'|'(';$^=')'^'[';$/='`'|'.';$_='('^'}';$,='`'|'!';$\=')'^ '}';$:='.'^'~';$~='@'|'(';$^=')'^'[';$/='`'|'.';$_='('^"\}";$,= '`'|'!';$\=')'^'}';$:='.'^'~';$~='@'|'(';$^=')'^'[';$/='`'|"\."; $_='('^ "\}"; $,='`'|'!';$\=')'^'}';$:='.'^'~';$~='@'|'(';$^ =( ')')^'[';$/='`'|'.';$_='('^'}';$,='`'|'!';$\= ')'^'}';$:='.'^'~';$~='@'|'(';$^=')'^'[';$/= '`'|'.';$_='('^'}';$,='`'|('!');$\= "\)"^ '}';$:='.'^'~';$~='@'|'(';$^=')'^'['; $/='`'|'.';$_='('^'}';$,='`'|('!');$\= ')'^'}';$:='.'^'~';$~='@'|'(';$^=(')')^ '[';$/='`'|'.';$_='('^'}';$,='`'|"\!";$\= ')'^'}';$:='.'^'~';$~='@'|'(';$^=')'^'['; $/='`'|'.';$_='('^'}' ;$,='`'|'!';$\="\)"^ '}';$:='.'^'~';$~='@' |'(';$^=')'^'[';$/= '`'|'.';$_='('^'}';$, ='`'|'!';$\=(')')^ '}';$:='.'^"\~"; $~='@'|'(';$^=')'^"\["; $/='`'|'.';$_='('^'}';$,="\`"| "\!"; ($\) =')' ^(( '}') );( $:)= ( '.' )^(( ( '~' ))); $~ = '@' |'(' ; ( $^) =(( (( (( ')' ))) )) ) ^(( '[' ));( ( $/) )=( '`') | '.' ;$_ ='(' ^ '}' ;$, ='`'|'!'; ( $\) =(( (( ( (( ')' )) ) )) ))^ ( ( (( '}' ) )));( $:) = (( '.' ) )^'~';$~='@'|'(';$^=')'^'[';$/='`'|'.' ;$_ ='('^'}';$,= '`'|'!' ; ( $\)=')' ^ '}' ; ( $:) =(( (( ( ( (( '.' ))) ) ))) ) ^ '~';$~="\@"| ( ( '('));$^=')' ^ '[' ; ( ( ( ( $/ ))) ) = ( (( ( (( ( '`')) ) ) )) ) |+ ( ( ( ( ( ( (( ( '.' )))))))));($_)= ( '(')^'}';$,= (( ( ( ( ( ( ( ( ( ( ( ( ( '`' ) ) ) ))) )) ) ) ) )))|'!';$\=')'^'}';$: = ( ( '.'))^'~';$~='@'|'(';$^= ( ( ( ')')))^'[';$/='`'|"\.";$_= ( ( ( '(')) )^'}';$,="\`"| '!'; ( ( ( $\)) ) = ')' ^ (( '}' ));$:='.'^'~';$~ =(( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( '@' )) ) ) ))))))))))) ) )))))))))))))|+ '(';$^=')'^('[');$/= '`'|'.';$_='('^'}';$,='`' |'!' ;$\= ')'^ '}'; ($:) ='.' ^'~' ;$~= '@'| '('; ($^) =')' ^'[' ;$/= '`'| '.' ;$_= '('^ '}'; $,='`' |'!' ;$\= ')'^ ( '}' );( $:) ='.'^'~' ; $~= '@' | '('; $^= ( ')' )^+ ( '[');$/='`' | '.' ;$_ = ( '(' )^+ ( ( '}' )); ( ( $,) )=( ( ( '`' ))) | ( '!' ); ( ( $\) ) =( ( ( (( ( (( ( ( (( ( ')') ))))))))) )))^(( '}' ) );( $:) =(( '.' ))^ '~' ; $~ =( '@')|'(' ;$^=')' ^+ ( ( (( (( '[') )) ) )) ;$/= (( ( ( ( '`' )))))|'.'; ( $_)='('^'}' ; ( ( $, ) ) = (( ( (( ( '`' ) )) ) ))| ( '!' );($\)= ( ')' )^'}' ; ( ( $:) )='.' ^ ( ( '~' ));$~= '@'|"\(";$^= ')'^ '[';$/ ='`' |'.';$_ ='('^'}';$,='`'|'!' ;$\= ')'^'}'; $:='.'^'~';$~='@'|'(';$^ =')' ^'[';$/= (( "\`"))| '.';$_="\("^ '}';$,='`'|'!';$\= (')')^ '}';$:='.' ^'~';$~="\@"| "\("; $^=')'^'[' ;($/)= '`'|('.');$_= '('^"\}"; $,='`'|'!';$\=')'^'}';$:='.'^'~' ;$~='@'|'(';$^=')'^'[';$/=('`')| '.';$_='('^'}';$,='`'|('!');$\= ')'^'}';$:='.'^'~';$~='@'|'('; $^=')'^'[';$/='`'|'.';$_='(' ^'}';$,='`'|'!';$\=(')')^ '}';$:='.'^'~';$~="\@"| '(';$^=')'^('[');$/= '`'|'.';$_=('(')^ '}';$,='`'| '!';$\=')'^"\}"; $:='.'^'~'; $~=('@')| '(';$^=')'^'[' ;$/='`'|'.' ;$_='('^"\}";$,= '`'|"\!";$\= ')'^'}';$:='.'^'~' ;$~='@'|"\("; $^=')'^'[';$/='`'|'.' ;$_='('^"\}"; $,='`'|'!';$\=')'^"\}"; $:='.'^'~';$~ ='@'|'(';$^=')'^"\[";$/= '`'|'.';$_='(' ^'}';$,='`'|'!';$\=')'^'}' ;$:='.'^'~';$~ ='@'|'(';$^=')'^'[';$/='`'| '.';$_='('^'}'; $,='`'|'!';$\=(')')^ '}' ;$: ='.'^'~' ;$~='@'|'(';$^=')' ^'[';$/ ='`'|'.';$_=('(')^ '}';$,= '`'|'!';$\=')'^'}' ;($:)= '.'^'~';$~='@'|'('; $^=')' ^'[';$/='`'|'.';$_= "\("^ '}';$,='`'|"\!";$\= ( ')') ^'}';$:='.'^'~';$~ = '@' |'(';$^=')'^'[';$/ = (( '`'))|'.';$_="\("^ ( (( '}')));$,='`'|'!'; ( ( ( ( ( ( ( $\)))))))=')'^"\}"; ( ( ( ( ( $:)))))='.'^'~';$~ ='@'| '(' ; ( ( $^))=')'^'[';$/ ='`'|'.' ;($_) = ( ( '('))^'}';$, = ( '`')|"\!"; ( $\) = ')' ^ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( '}')))))) ) ) ) ))))))))))))) ) ) )))))))) ; ( ( $:))='.'^'~'; ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( $~))))))) )))))))))))))) ))))))))))='@'|"\("; $^=')'^'[';$/='`'|'.';$_= '('^'}';$,=('`')| '!';$\= ')'^'}';$:='.'^'~';$~ ='@'|'(' ;$^=')'^'[';$/='`'|'.';$_='('^'}';$, ='`'|'!';$\=')'^'}';$:='.'^'~';$~="\@"| '(';$^=')'^'[';$/='`'|'.';$_='('^('}');$,= '`'|'!';$\=')'^'}';$:='.'^'~';$~='@'|'(';$^= ')'^'[';$/='`'|'.';$_='('^'}';$,='`'|"\!";$\= ')'^'}';$:='.'^'~';$~='@'|'(';$^=')'^ '[' ;$/='`'|'.';$_='('^'}';$,='`'|'!';$\= ')' ^'}';$:='.'^'~';$~='@'|'(';$^=')'^'[' ;$/='`'|'.';$_='('^'}';$,='`'|'!';$\= ')'^'}';$:='.'^'~';$~='@'|'(';$^="\)"^ '[';$/='`'|'.';$_='('^'}';$,='`'|"\!"; $\=')'^'}';$:='.'^'~';$~='@'|('(');$^= ')'^'[';$/='`'|'.';$_='('^'}';$,="\`"| '!';$\=')'^'}';$:='.'^'~';$~='@'|'('; $^=')'^'[';$/='`'|'.';$_='('^"\}";$,= '`'|'!';$\=')'^'}';$:='.'^('~');$~= '@'|'(';$^=')'^'[';$/='`'|"\.";$_= '('^'}';$,='`'|'!';$\=')'^"\}";$:= '.'^'~';$~='@'|'(';$^=')'^('[');$/= '`'|'.';$_='('^'}';$,='`'|"\!";$\= ')'^'}';$:='.'^'~';$~='@'|('(');$^= ')'^'[';$/='`'|'.';$_='('^"\}";$,= '`'|'!';$\=')'^'}';$:='.'^"\~";$~= '@' |'(';$^=')'^'[';$/='`'|'.';$_='('^ ( '}');$,='`'|'!';$\=')'^('}');$:= '.'^ '~';$~='@'|'(';$^=')'^('[');$/= '`'|'.' ;$_='('^'}';$,='`'|'!';$\=')'^ '}';$:='.'^ '~';$~='@'|'(';$^=')'^'[';$/= '`'|'.';$_='(' ^'}';$,='`'|"\!";$\= (( ')'))^'}';$:='.'^ '~';$~='@'|('(');$^= ( ')')^'[';$/='`'|'.' ;$_='('^'}';$,="\`"| ( ( '!'));$\=')'^'}'; $:='.'^'~';$~='@'|'(' ; $^=')'^'[';$/= '`'|'.';$_='('^'}';$, ='`'|"\!"; ($\) =')'^'}';$:='.' ^'~';$~ =(( '@'))|('(');$^= ')' ^+ '[';$/='`'|"\."; ( $_)='('^"\}";$,= '`'|'!';$\="\)"^ '}';$:='.'^"\~"; もしあなたが心からLarryを偶像視するのであれば、彼の周りに 枠をつけるかもしれません: print sightly( { Shape => 'larry2', BorderGap => 3, BorderWidth => 2, SourceFile => 'helloworld.pl', Regex => 1 } ); Cという形は、Ryan Kingにより寄稿されたマンガです: ''=~('('.'?'.'{'.('`'|'%').('['^'-').('`'|'!').("\`"| ',').'"'.('['^'+').('['^')').('`'|')').('`'|'.').('[' ^+ (( (( (( (( (( (( '/'))))))))))) )) .( '{'^'[').'\\'.'"'.('`' |+ (( '('))).('`'|'%').('`'|',' ). +( '`'|(',')).( '`'|'/'). ('{'^ (( (( '['))))).('[' ^',').( (( '`' )) |+ '/' ).('['^')') .("\`"| ( ',' )) .( '`' |"\$").'\\'. '\\'. ( '`' |+ (( '.' ))).('\\'). '"'. ( (( (( (( ';') )))))).''. ('!' ^ (( (( '+'))) )). '"' . ( (( (( (( '}')))))) ) . ( ( ( (( (( (( ')')))))) )))); $:='.'^'~';$~=('@')| (( (( '(')))); $^ ="\)"^ (( (( ( (( (( (( '['))))) ))) ) ) ) ;( $/ )= '`'|'.'; $_ = ( ( ( ( (( (( (( '(')))) )) ) ) ) )^ (( (( '}'))) ); $, =( '`' )| (( "\!")); ( $\)=')'^ '}'; $: =( (( '.')))^ ( '~'); ($~)= ( (( (( (( '@')))))) )|"\("; $^=')'^'[' ;( $/ )="\`"| '.';$_='(' ^'}';$,='`' |+ (( '!')) ; $\=(')')^ ( "\}"); $: =( ( '.')) ^'~' ; ($~) =( (( ( ( '@' ) ))) )| (( '(' ) ); ( ( $^ )) =( (( ( ( "\)")))))^ ( (( (( '[' )) ) )) ;( ( $/ )) =( (( ( (( ( ( (( (( '`'))))) ) )) )) )) |+ (( (( (( '.'))))));$_='('^'}';$,='`'|'!';$\=')'^'}';$:='.'^'~' ;$~='@'|'(';$^=')'^'[';$/='`'|'.';$_='('^'}';$,="\`"; =head2 Just another Perl hacker より意欲的にして、大きく自分自身を出力するIを作ってみましょう。 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 } ); これは動きます。しかし以下のものを: $x =~ tr/!-~/#/; を以下のように変更すると: $x =~ s/\S/#/g; 生成されたプログラムは奇妙な動きをして、うまく動きません。というのも それが正規表現の内側で走り、Perlの正規表現エンジンが再入可能(reentrant) ではないからです。この場合、以下のようにして逃げなければなりません: print sightly( { Shape => 'japh', SourceString => $src, Regex => 0 } ); これは生成された見た目の良いプログラムを代わりにCを通して実行します。 Regex => 1を使いたいのであれば、変換されるプログラムが、正規表現とC<$_>の 使い方に注意していることを確実にしてください。 元のI、別名Iに似ている Iを生成するためには、以下のようにしてください: print sightly( { Shape => 'merlyn', SourceString => 'Just another Perl hacker,', Regex => 1, Print => 1 } ); 生成されるもの: ''=~('('.'?'.'{'.('[' ^'+').('['^')').('`'|')').( '`'|'.').('['^'/').'"'.('`'^'*') .('[' ^'.') .('[' ^'(') .('[' ^'/') .('{'^ '[').( "\`"| '!').( '`'| '.').( '`'| ( ( '/'))). ('[' ^ ( ( '/'))).( '`'| ( ( ( ( '('))))). ('`'| ( ( ( ( '%'))))). ('['^ ( ( ( ( ')'))))). ('{'^ '[') .( ( (( ('{'))))^ '+'). ( '`'|'%' ).("\["^ ')').('`' |',').('{'^ '[').('`' |'(').('`' |"\!").( '`'|'#').( ('`')| '+').( '`'|'%') .('['^')') .(( ',' )). '"' .('}'). "\)");$:= ('.')^ ( "\~"); $~='@'| ('(');$^= (( ')' )) ^ (( '[' )) ;($/)= '`'|'.'; $_='('^'}' ; $,='`'|'!' ;($\) =(')')^ ( '}' );($:) = '.' ^'~'; ( ( ( $~) ) )= ( ( ( '@' ) ) ) | ( ( ( '(' ) ) ) ; ( ( ( $^ ) ) ) = ( ( ( ( ( ( ( ( ( ')')))))))))^'[' ; # ; # ; # ; # ;# ; # ; # ; #; # ; #; #; # ; # ; # ;# ; # ; # ;#;#; # ; # ; # ; # ; # ; # ; # ; # ; # ; # ; # ; # ; # ; #;# ;# ;#;#;#;#; =head2 鏡で見るBuffy I<見た目のよい>エンコードはコンパクトではないため、あなたは時折、 Iの超現実的な形式を楽しんでいることがわかるかもしれません。 そこでの勝者は以下のような最も小さいFを持ったものです: sightly.pl -r -f program_to_be_converted >f.tmp (キー)ストロークの数を減らすことを別にすれば、正規表現を避け、 英数字を見た目のよいもので置き換えるべきです。それは見た目のよい エンコーディングを必要としません。 説明するために、I<鏡で見るBuffy>(=Buffy looking in the mirror)を 作成する、面白い問題を考えてみましょう。Fから始めましょう: open$[;chop,($==y===c)>$-&&($-=$=)for@:=<0>; print$"x-(y---c-$-).reverse.$/for@: EyeDropsが生成するプログラムには後ろに空白が入っていないことに 注意してください。それが、上記のプログラムをおかしくします。 鏡で見るBuffyは、これで以下のように作成することができます: sightly.pl -r -f k.pl -s buffy2 >b.pl cat b.pl (Buffyの顔を表示します) perl b.pl (鏡で見るBuffyを表示します) チィッ。これはIの図形を2つ必要とします。何をするべきでしょうか? あなたは必要とされる数の空白を追加するため、各行に追加するための ポスト・プロセッサ・プログラム、ここではFを 書く事が出来ます: chop,$==y===c,$=<$-or$-=$=for@a=<>; print$_.($"x($--length)).$/for@a このプログラムがあれば、Fをより短く書く事が出来ます: open$%;chop,print+reverse.$/for<0> そして最後に、以下のようにしてI<鏡で見るBuffy> を生成します: sightly.pl -r -f kk.pl -s buffy2 >b.pl perl pp.pl b.pl >bb.pl この例では、しかしながら、C 属性(FではC<-m> スイッチ)が、後ろの空白を必要とすることなく、より直接的な解決方法を 提供します: sightly.pl -mr -f k.pl -s buffy2 >buffy.pl cat buffy.pl (Buffyの顔を表示) perl buffy.pl (鏡で見たBuffyを表示) 生成される F: ''=~('(?{'.( '`'|'%').('['^'-' ).('`'|'!').('`'|',' ).+ ( '"' ).( ( '`' )|+ ( '/' )). ( '[' ^(( ( '+' ))) ).('`' |(( '%' ))). ( '`' |(( '.') ) ).+ ((( (( ( ((( ((( ( ( ((( ((( ( '\\'))) ))) ) ) ) ) ) )))) )))))) .'$[;' . ( ( ( (( ( ( ( ( ( (( ( ( (( ( ( ( ( ( '`') )))) ) ) ) ) ))) ) ) ))) ) ) )| ( ( ( ( (( '#' ) ) ) ))) ).(('`')| ('(')).( '`'|'/'). ('['^'+') .',(\\$' .'=='.('[' ^'"') . '==='.+( '`'|'#').')' . '>\\$-' .'&&(\\$-=\\' . '$=)'.( '`'|'&').('`' | ( '/')).( '['^')').'\\' . '@:=<' . ('^'^(('`')| "\.")). ( '>').(';').( '!'^'+' ) .('['^'+'). ('['^')' ).('`'| ')').("\`"| "\.").( ( ('['))^ "\/").'\\$\\"'.( ( "\[")^ ( ( ( ( "\#"))))). ( ( '-')) . ( ( ( ('(')))).( ( ( '[')) ^ ( ( '"'))).'--' . '-'. ( ( ( '`'))|'#'). ( ( ( ( '-')))). ( ( ( ( ( '\\' ) ) ) ) ) . ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( '$'))))))))))))))))))))))))).'-).'.('['^ ( ( ( ')')))).('`'|'%').('['^'-').('`'|'%').(('[')^ ( ( ')'))).('['^'(').('`'|'%').'.\\$/'.('`'|'&').( ( ( '`'))|'/').('['^')').'\\@:'.('!'^'+').'"})');$:= ( ( '.'))^'~';$~='@'|'(';$^=')'^'[';$/='`'|'.';$_='(' ; しかし人によっては目に、プレインな見た目のよいエンコーディングの ほうが楽しいと思うかもしれませんが、これはおそらくよりキレイな 解決法でしょう。 面白いことに、鏡像ではなく、顔を上下逆さまに表示することは、 以下の様にして、より簡単に解決されます: open$%;print+reverse<0> そして自分自身を表示したり: open$%;print<0> あるいは空白以外をC<'#'>で置き換えて自分を表示することも簡単です: open$%;print+map{y;!-~;#;;$_}<0> =head2 ラクダの宙返り 前の章のBuffyの例を、実行したときに画面を宙返りするような能力を持った ラクダの形をしたプログラムを生成するように拡張しましょう。 生成するプログラム、Fから始めます: use Acme::EyeDrops qw(sightly); my $src = <<'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 $src =~ tr/\n//d; my $prog = sightly( { Regex => 1, Compact => 1, Shape => 'camel', SourceString => $src } ); my @a = split(/\n/, $prog); my $max = 0; length > $max and $max = length for @a; $_ .= ' ' x ($max - length) for @a; print " $_ \n" for @a; Compact属性の使い方について注意してください。ここでの必要なのは 上記のプログラムを1つのラクダの形に絞るためです。 これを実行すると: perl gencamel.pl >camel.pl Fを生成します: ''=~('(?{'.( ('`')| '%').('['^'-'). ('`'|'!'). ('`'|',').'"\\$~=' .('['^'+') .('`'| '/').('['^'+').'||'. "'"."'".';'.('`'|'/' ).('['^'+').('`'|'%'). ('`'|'.').('\\$%;').( '['^'"').(',!-~,#,,').( '['^'(').',(.).,\\' .'$+,'.('`'|"'").('['^'(') .',\\$~&&(\\$' .'_='.('['^')').('`'|('%')).( '['^'-').('`'| '%').('['^')').('['^'(').(('`')| '%').')'.("\`"| '&').('`'|'/').('['^"\)").'\\@~='.( '`'|"'").("\["^ ')').('`'|'%').('['^'+').('\\$|--,('). "'"."'".(')').( '['^'#').('^'^('`'|'/')).(':'&'=').',<'. ('^'^('`'|'.') ).'>;\\@;='.('`'|'-').('`'|'!').('['^'+') .'~~'.('['^')' ).('`'|'%').('['^'-').('`'|'%').('['^')'). ('['^'(').('`'|'%').','.('['^')').('`'|'%').('['^'-').('`' |'%').('['^')').('['^'(').('`'|'%').'\\@~;'.('`'|'-').('`'| '!').('['^'+').'\\{'.('['^'(').('['^'"').('['^'(').(('[')^ '/').('`'|'%').('`'|'-').'\\$^'.('`'^'/').'=~'.('{'^"\,").( '`'|')').('`'|'.').'?'.('`'^'#').('`'^',').('{'^'(').(':'). "'".('`'|'#').('`'|',').('`'|'%').('`'|'!').('['^')')."'". ';(\\$-=\\$_%'.('^'^('`'|'-')).')||(--\\$|,'.('`'|'-' ).( '`'|'!').('['^'+').'\\$_='.('['^')').('`'|'%').('[' ^(( '-'))).('`'|'%').('['^')').('['^'(').('`' |('%')). ',' .'\\@~,\\@;);'.('['^'+').('['^(')')).( '`'|')' ).( "\`"| '.').('['^'/').'\\$\\"'.("\["^ ('#')). '(' .'\\$=/'.('^'^('`'|'-')).'*'. (('`')| '!' ).("\`"| '"').('['^ "\("). '\\$|' .+ ('*').( '^'^('`' |',')) .'-\\' .+ '$-),'. '\\$_,'. '\\$' .'/'. ( ('`')| ('&')).( '`'| '/') .('['^ ')').'\\' .'$' .'-' .'&'. (('^')^( '`'| '/') ).'?' .'\\@;' .':' .''. '\\' .'@~;' .''. ('[' ^'(' ).( '`'| ',') .''. ((( '`' ))| '%' ).( '`' |(( '%' ))) .+( '[' ^(( '+' ))) .+ (( '!')). (( (( '\\') )) ). '$%\\}'. (( ((( '\\' ))))) .+ '$' .'%..' .''. ((( '^') )^("\`"| '/' )).( "\^"^( ('`')| ('/'))). '"})'); I<注意: Perlに関連付けてラクダの画像を使用することは O'Reilly & Associates, Inc.の商標です。許可を受けて使用しています>。 以下の様にしてFを実行することができます: perl camel.pl 通常の方向に宙返りするラクダ perl camel.pl b 後ろの方向に宙返りするラクダ perl camel.pl please do a backward somersault 同じこと そのヘッダ行の後に空行も追加する限り、Fの先頭に C<#!/usr/bin/perl -w>という行を入れてもかまいません。 =head2 12,032種類のラクダ 上記の宙返りするラクダと似た方法で、実行したとき12,032種類の異なる ラクダを吐き出す、ラクダの形をしたプログラムを作成します。 いつものように、生成するプログラムFから始めます: use Acme::EyeDrops qw(sightly); my $src = <<'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 $src =~ tr/\n//d; my $prog = sightly( { Regex => 1, Compact => 1, Shape => 'camel', SourceString => $src } ); my @a = split(/\n/, $prog); my $max = 0; length > $max and $max = length for @a; $_ .= ' ' x ($max - length) for @a; $\ = "\n"; print ' ' x ($max+2); print " $_ " for @a; print ' ' x ($max+2); これを実行し: perl gencamel.pl >camel.pl Fを生成します。これは以下の様に実行することができます: perl camel.pl 通常のラクダ perl camel.pl q quine (プログラムがそれ自身を出力) perl camel.pl m 鏡像 (鏡で見るラクダ) perl camel.pl i 反転したラクダ perl camel.pl u 上下逆さまのラクダ perl camel.pl r 回転したラクダ perl camel.pl h 水平方向につぶれたラクダ perl camel.pl v 垂直方向につぶれたラクダ そしてさらに上記のオプションと組み合わせることができます。 それぞれの組み合わせは異なるラクダを生成します。例えば: perl camel.pl uri は、大きな、あごひげを蓄え、ポニーテールで、メガネをかけ、 絞り染めのTシャツを着たラクダを生成します。 :) Fはオプションで、ラクダを埋める文字を指定する、 第2の引数を受け取ることが出来ます。(デフォルトはC<#>)。 例えば: perl camel.pl hv #で埋められた小さなラクダ perl camel.pl hv "$" $で埋められた小さなラクダ なぜ12,032種類のラクダなんでしょうか?主たるオプションq, m, i, u, r, h, vは 128の異なるラクダを生成します。そして第2パラメータとして94の出力可能な 文字が利用できます。合計を求めると 128 * 94 = 12,032種類のラクダになります。 =head2 裸で腕相撲 ミュンヘン(Munich)でのY::E 2002での最後のオークションは大叙事詩的な 運動競技が呼び物でした。これを以下のようにして思い出すことができます: print 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 =head2 シェルピンスキーの三角形 シェルピンスキーの三角形(=Sierpinski triangle)を生成するプログラムは さまざまなメーリングリストやPerl monksでも人気を証明してきました。 単純で簡潔なシェルピンスキーの三角形を生成するプログラム、Fは 以下の通りです: #!perl -l $x=2**pop;print$"x--$x,map$x&$_?$"x2:"/\\",0..$y++while$x これはMtv Europeにより、元のAdam Antonikのプログラムをワン・ストローク 改善したものとして、golf@perl.orgへ14-sep-2002に投稿されました。 これを実行すると: perl siertri.pl 4 2**4行のシェルピンスキーの三角形を表示します。 (Acme::EyeDrops 1.13で)Mtvのプログラムが最も短いと示すことは、 以下のいくつかのようにハードにC<$^F>を利用することによって、より短くするよう、 Adam Antonik と Eugene van der Pijllを刺激しただけでした: -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/^ / シェルピンスキーの三角形を作成する面白く判りにくいプログラムは: #!/usr/bin/perl -l s--@{[(gE^Ge)=~/[^g^e]/g]}[g^e]x((!!+~~g^e^g^e)< $src, Regex => 1, Compact => 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' } ); 生成されるもの: ''=~('(?{'.('`'|'%').('['^'-').('`'|'!').('`'|"\,").'"\\$-=!\\$%<<('.( '['^'+').('`'|'/').('['^'+').'||'.('^'^('`'|'*')).');'.('['^'+').('['^ (( (( (( (( (( (( ')') )) )) )) )) )) )) .(('`')| (( (( (( (( (( (( ')') )))) )) )) )) )) .( (( (( (( '`'))))))|'.').( (( (( (( (( (( (( '[') )))) )) )) )) )^ (( (( (( (( '/'))))) )))).''. (( (( (( (( (( (( (( (( '\\' )))) )))) )))) )) )) .+ (( (( (( (( (( (( (( (( (( '$')))))))))))))))))).'\\"'.('[' ^+ (( (( (( (( (( '#') )))) )) )) )) .+ (( (( (( (( '\\')))) )))).'$' .+ (( (( (( (( (( (( (( '-') )))) )))) )))) ). (( (( (( (( (( (( (( (( (( (( (( ','))))))))))))) ))))))))).("\`"| (( (( (( (( (( (( (( (( '-') )))) )))) )))) )) )) .( (( (( (( (( (( (( (( (( (( '`'))))) )))))))) )))))|(( '!'))).( (( (( (( (( (( (( (( (( (( (( (( (( '[') )))) )))) )))) )))) )))) )))^ '+') .+ (( (( (( (( (( (( (( (( (( (( (( (( (( (( (( (( (( (( (( '(')))))))))))))))))))))))))))))))))))))).'\\$-&\\$_?'."'".('{'^ (( (( (( '['))))))).('{'^'[')."'".':'."'".'/\\\\\\\\'."'".',\\$%..\\$.++),\\$/' .('['^',').('`'|'(').('`'|')').('`'|',').('`'|'%').'\\$---"})');$:='.' =head2 闘うディンゴ(Dueling Dingos) TPR02 Perlゴルフ・トーナメントの間に、I<`/anick>は彼の経験について 述べたIという詩を書きました。 彼の動く詩を書き出すプログラムを以下のように作ることが出来ます: 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 ここでは、生成される2577行ものプログラムは再び生成されません。 I<`/anick>のTPR02での苦悩をまとめる、より短いプログラムを生成するためには 以下のようにします: 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 生成されるもの: ''=~('('.'?'.'{'.( '['^'+').('['^')').('`'| ')').('`'|'.').('['^'/').'"' .('`'^'-').('['^'"').('{'^'[').( '`'|'(').('`'|'%').('`'|'!').("\`"| '$').('{'^'[').('`'|')').('['^('(')).( '{'^'[').('`'|'(').('['^'.').('['^"\)").( '['^'/').('`'|')').('`'|'.').('`'|"'").','. ('{'^'[').('`'|'-').('['^'"').('{'^'[').('['^ ')').('`'|')').('`'|"'").('`'|'(').('['^'/').( '{'^'[').('`'|'%').('['^'"').('`'|'%').('{'^'[' ).('`'|'&').('`'|'%').('`'|'%').('`'|',').(('[')^ '(').('{'^'[').('`'|',').('`'|')').('`'|'+').("\`"| '%').('{'^'[').('`'|')'). ('['^ ('/')). "'".('['^'(').('{'^'['). ("\`"| "'").('`'|'/').('`'|')' ).''. ('`'|'.').('`'|"'").('{' ^'[') .('[' ^'/').('`'|'/').(('{')^ '['). ('['^'+' ).('`'|'/').('['^'+'). ('!'^ '+').('`' |',') .('`'|(')')).( "\`"| '+').('`' |'%' ).('{'^'['). ('`'| '!').('{' ^ ('[')).( "\`"| '-').('`' | "\/").( "\["^ '(').('[' ^ '*' ).( '['^'.' ) .+( ( ( ( ( ( ( '`'))) ) )) | ( ( ')')) ) . ( ( '[')^ ( ( '/')) ) .('`'| '/'). ( "\{"^ '[' ).('`' |'$') . ('['^ ( ( ( ')')) ) ) . ('`'| ( ')')) . ( "\`"| ( '.')) . ( "\`"| ( ( ( '+'))) ) .( ( ( "\`"))| ( (( ( ( ')')))))) . +( ( ( '`'))|'.').( ( (( ( ( '`')))))|"'").('{'^'[').( (( ( '`')))|'&').('['^')').('`'| (( ( '/')))).('`'|'-').('{'^'['). ('`' |'!').('`'|'.').('{'^'[').('`' | '%').('['^'#').('['^'+').("\["^ ( ')')).('`'|'%').('['^('(')).( '['^'(' ).('`'|'/').('{'^'[').("\`"| '!').('`'|'$').('`'|"\$").( '`'|')').(('`')| ( '#')).('['^'/').("\{"^ ( ( '['))).('['^',').('`'|')') . ( '['^'/').('`'|'(').('{'^'[').( ( ( '`'))|'(').('`'|')').('`'|"'").( ( ( '`'))|'(').('!'^'+').('`'|('"')).( ( ( '`'))|',').('`'|'/').('`'|('/')).( ( ( '`'))|'$').('{'^'[').('['^'+').('['^ ( ( ')'))).('`'|'%').('['^'(').('['^'(') . ( '['^'.').('['^')').('`'|'%').(',').( ( ( '{'))^'[').('`'^')').('{'^'[').('['^ ( ( ','))).('`'|'!').('`'|'.').('['^'/') . ( '{'^'[').('['^'/').('`'|'/').('{'^ ( ( '['))).('`'|'#').('['^')').(('`')| ( ( '!'))).('['^',').('`'|',').('{'^ ( ( '['))).('['^'(').('`'|('/')).( ( ( '`'))|'-').('`'|'%').('['^ ( ( ','))).('`'|'(').('`'| ( '%')).('['^')'). +( (( '`')) | ( "\%")).( ( ( '{'))^'[' ) . ( ( '`')|'$').( ( ( ( ( '`'))))|'!') . ( ( ( '`'))|'-').( ( ( ( ( '['))))^'+') . ( ( ( '{'))^'[').( ( ( ( ( '`'))))|'!' ) . ( ( '`')|'.' ).('`'|'$' ) . ( ( '{')^'[').('`'| ('$')).( '`'| '!' ) . ('['^')').('`'|'+') .('{'^'[').('`'| ( '!')).('`'|'.').('`'|'$').('!'^"\+").( ( '[')^'*').('['^'.').('`'|')').('`'|'%' ).('['^'/').('{'^'[') .('`'|'!'). ('`'|('.')).( '`'|('$')).( '{'^'[' ).( '`' ^+ ( ( ( (( ( ( ( (( ( ( ( (( ( ( ( (( ( ( ( ')') ) ) ) )) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) . ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( '{')))) )))))) ))))) )^'[' ).''. ('`'| '#').('`'|'/').('`'|'.').('['^'(').(('`')| ')').( '`'|'$').('`'|'%').('['^')').('{'^('[')).( '`'|'.'). ('`'|'%').('['^'-').('`'|'%').('['^')').('{'^ '[' ).('['^'/').('`'|'/').('{'^'[').('['^'/').( '`' |'/').('['^'.').('`'|'#').('`'|'(').("\{"^ '[' ).('`'|'!').('{'^'[').('`'|'+').('`'|'%' ).( '['^'"').('`'|'"').('`'|'/').('`'|'!').( '['^ ')').('`'|'$').('{'^'[').('`'|('!')).( '`'| "'").('`'|'!').('`'|')').('`'|"\."). '.'. ('!'^'+').'"'.'}'.')');$:='.'^('~');$~= '@'|'(';$^=')'^'[';$/='`'|'.';$_='(' ^'}';$,='`'|'!';$\=')'^'}';$:= '.'^'~';$~='@'|('(');$^= ')'^'[';$/='`'|'.' =head2 バイナリ・ファイルのエンコーディング ちょっと待ってください、まだまだあるんです。 あなたはバイナリ・ファイルも コード化することができます。 print sightly({Shape => 'camel,mongers', SourceFile => 'some_binary_file', Binary => 1, Print => 1, Gap => 3 } ); これはIよりもキレイです。 以下にFでバイナリ・ファイルをエンコード/デコードする方法を示します。 エンコード: sightly.pl -g3 -bps camel,mongers -f some_binary_file >eyesore デコード: perl eyesore >f.tmp それが動くかを確認: cmp f.tmp some_binary_file =head2 ゆっくりしたい日 本当にゆっくりしたい日には、Unix端末に座り、以下のようにタイプ することができます: sightly.pl -r -s camel -f helloworld.pl >t1.pl cat t1.pl perl t1.pl この小さなプログラムにはラクダが1頭だけ必要です。 sightly.pl -r -s camel -f t1.pl >t2.pl cat t2.pl perl t2.pl フーム、これでラクダが14頭。 sightly.pl -r -s camel -f t2.pl >t3.pl ls -l t3.pl cat t3.pl perl t3.pl ラクダ195頭。563,745バイト。ウーン、遅くなった。 これまでに書かれた最も大きくって、遅いIプログラムじゃない? sightly.pl -r -s camel -f t3.pl >t4.pl ls -l t4.pl cat t4.pl perl t4.pl ラクダ2046頭。5,172,288バイト。メモリがないだって! =head2 Buffyはクリケットに行った Buffyファンは彼女の文字を回転したいかもしれません: print sightly( { Shape => 'buffy', Rotate => 0, # try 270, 90 and 180 RotateType => 1, # try 0, 1, 2 SourceFile => 'helloworld.pl', Regex => 1 } ); あるいは彼女をポニーに乗せたいかもしれません: print sightly( { Shape => 'buffy3,buffy4,riding,a,pony', SourceString => "This is how Catherine the ". "Great died.\n", Gap => 2, Regex => 1, Print => 1 } ); 一方、クリケットのファンは以下のように比較するかもしれません: print sightly( { Shape => 'cricket', SourceFile => 'helloworld.pl', Regex => 1 } ); これは以下のものを生成します: '?' =~+( "\(". "\?". "\{".( ('`')| '%').( ('[')^ '-').( "\`"| '!').( '`'|',') .'"'.('[' ^'+').('[' ^"\)").( '`'|"\)").( '`'|'.') .('['^'/') .(('{')^ '[').'\\'. '"'.(('`')| '(').('`' |'%').('`'|',' ).("\`"| "\,").( '`'|'/') .('{'^'['). (('[')^ ',').('`'|'/').(('[')^ "\)").( '`'|',').('`'|'$').''. ('\\'). '\\'.('`'|"\.").'\\'. ('"'). ';'.('!'^'+').('"'). '}'.')');$:='.'^'~';$~='@'| '(';$^=')'^'[';$/='`'|'.';$_ ='('^'}';$,='`'|'!';$\=')'^ '}';$:= '.'^'~';$~="\@"| '('; $^=')'^"\[";$/= '`'|'.';$_='('^ '}';$,='`'|"\!"; $\=')'^('}');$:= '.'^'~';$~="\@"| '(';$^=')'^"\["; $/='`'|'.';$_='(' ^'}';$,='`'|'!';$\= ')'^'}';$:='.'^'~';$~= '@'|'(';$^=')'^('[');$/= '`'|'.';$_='('^'}';$,='`' |'!';$\=')'^'}';$:='.'^'~'; $~='@'|'(';$^=')'^'[';$/='`'| ( '.');$_='('^'}' ;$,='`'|"\!"; $\ =')'^"\}";$:= '.'^('~');$~= '@' |'(';$^=')'^ '[';$/=('`')| '.';$_=('(')^ '}';$,=('`')| '!';$\=(')')^ '}';$:=('.')^ '~';$~='@'|'(' ;$^=')'^'['; $/='`'|('.');$_= '('^"\}";$,= '`'|'!';$\=')'^'}' ;$:='.'^'~' ;$~='@'|('(');$^= ')'^"\[";$/= '`'|'.';$_='(' ^'}';$,='`'| '!';$\= ')'^'}';$:= "\."^ '~';$~='@'| "\("; $^=')'^'[' ;$/= '`'|'.'; $_= "\("; そしてこれは: print sightly( { Shape => 'cricket', Invert => 1, BorderWidth => 2, SourceFile => 'helloworld.pl', Regex => 1 } ); これを生成します: ''=~('('.'?'.'{'.('`'|'%').('['^'-').('`'|'!').('`'|(',')). '"'.('['^'+').('['^')').('`'|')').('`'|'.').('['^'/').('{'^ '[').'\\'.'"'.('`'|'(' ).('`'|'%').('`'|',').('`'|"\,").( '`'|'/').('{'^"\[").( '['^',').('`'|'/').('['^')').('`'| ',').('`'|'$').'\\'. '\\'.('`'|'.').'\\'.'"'.';'.("\!"^ '+').'"'.'}'."\)"); $:='.'^'~';$~='@'|'(';$^=')'^'[';$/ ='`'|'.';$_="\("^ '}';$,='`'|'!';$\=')'^'}';$:='.'^'~' ;$~='@'|"\(";$^= ')'^'[';$/='`'|'.';$_='('^'}';$,='`'| '!';$\=')'^'}'; $:='.'^'~';$~='@'|'(';$^=')'^('[');$/= '`'|'.';$_='(' ^'}';$,='`'|'!';$\=')'^'}';$:='.'^"\~"; $~='@'|'(';$^ =')' ^'[';$/='`'|'.';$_='('^"\}";$,= '`'|"\!";$\= ')' ^'}';$:='.'^'~';$~='@'|'(';$^= ')'^'[' ;$/= '`'|'.';$_='('^'}';$,='`'|'!' ;$\=')' ^'}'; $:='.'^'~';$~='@'|'(';$^=')' ^'['; $/='`'| '.';$_='('^'}';$,='`'|'!';$\= "\)"^ '}';$:= '.'^'~';$~='@'|'(';$^=')'^'[' ;$/ =('`')| '.';$_='('^'}';$,='`'|'!';$\= (( ')'))^ '}';$:='.'^'~';$~='@'|'(';$^= (( ( ')') ))^'[';$/='`'|'.';$_="\("^ (( (( '}'))));$,='`'|'!';$\=')'^ '}' ;( $:)='.'^'~';$~='@'|'(';$^ =')' ^+ '[';$/='`'|'.';$_='('^'}' ;($,)= (( '`'))|'!';$\=')'^"\}";$:= '.'^'~' ;$~='@'|'(';$^=')'^'[';$/ =('`')| '.';$_='('^'}';$,=('`')| "\!";$\= ')'^'}';$:='.'^('~');$~= '@'|"\("; $^= ')'^'[';$/='`'|('.');$_= '('^'}';$, ="\`"| '!';$\=')'^'}';$:=('.')^ '~';$~='@'|('(');$^= ')'^'[';$/='`'|('.');$_= '('^'}';$,='`'|"\!"; $\=')'^'}';$:='.'^"\~"; $~='@'|'(';$^=(')')^ '[';$/='`'|'.';$_="\("^ '}';$,='`'|('!');$\= ')'^'}';$:='.'^"\~";$~= '@'|'(';$^=')'^"\["; $/='`'|'.';$_='('^"\}"; $,='`'|'!';$\="\)"^ '}';$:='.'^'~';$~="\@"| '(';$^=')'^'[';$/= '`'|'.';$_='('^'}';$,= '`'|'!';$\="\)"^ '}';$:='.'^'~';$~='@' |'(';$^=')'^'[' ;$/='`'|'.';$_="\("^ '}';$,='`'|'!'; $\=')'^'}';$:="\."^ '~';$~='@'|'(' ;$^=')'^'[';$/='`' |'.';$_="\("^ '}';$,='`'|'!';$\ ="\)"^ "\}"; $:= '.'^'~';$~="\@"| '(';$^= ')' ^"\["; $/='`'|"\.";$_= '('^'}'; ( $,)='`'| '!';$\=')'^'}' ;$:='.'^ '~';$~="\@"| '(';$^=(')')^ "\[";$/= '`'|('.');$_= '('^"\}";$,= '`'|'!'; $\=')'^'}';$:= '.'^'~';$~= '@'|"\("; $^=')'^"\["; $/='`'|'.' ;$_=('(')^ '}';$,='`'| ('!');$\= ')'^('}');$:= '.'^'~';$~ =('@')| '(';$^=')'^"\["; $/='`'|'.'; $_='(' ^'}';$,='`'|'!';$\=')' ^'}';$:=('.')^ "\~"; $~='@'|'(';$^=')'^"\["; $/='`'|'.';$_='(' ^(( '}'));$,='`'|('!');$\= ')'^'}';$:='.'^"\~"; $~ ='@'|'(';$^=')'^'[';$/ ='`'|'.';$_='('^'}';$, =(( '`'))|'!';$\=')'^"\}"; $:='.'^'~';$~='@'|'(';$^= ')'^ '[';$/='`'|'.';$_='('^'}';$,='`'|'!';$\=')'^'}';$:='.'^'~'; $~='@'|'(';$^=')'^'[';$/='`'|'.';$_='('^'}';$,='`'|"\!";#;# あるいは、これは: print sightly( { Shape => 'cricket', Invert => 1, BorderWidth => 1, Reduce => 1, SourceFile => 'helloworld.pl', Regex => 1 } ); これを生成します: ''=~('('.'?'.'{'.('`'|('%')).( '['^"\-").( '`'|'!').('`'|',' ).'"'.('[' ^'+').('['^')').( '`'|')'). ('`'|'.').('['^'/' ).("\{"^ '[').'\\'.'"'.('`'| "\(").( (( '`'))|'%').('`'| ',') .( '`'|',').("\`"| '/' ).( '{'^'[').("\["^ (( ',') )).('`'|"\/").( ( (( '[')))^')').( (( ( '`')))|',').( '`' | '$').'\\'.''. '\\' .('`'|"\."). '\\'. (( '"'))."\;".( '!'^"\+"). '"'.'}'.')') ;$:=('.')^ '~';$~="\@"| '(';$^=')' ^'[';$/='`'| ('.');$_= '('^'}';$,= '`'|'!'; $\=')'^'}' ;$:='.' ^"\~";$~= '@' |+ ( '(');$^= ')'^ '['; $/='`'| '.'; $_='(' ^"\}"; ($,)= ('`')| "\!"; $\=')'^ "\}"; ($:) ='.'^'~';$~ =('@')| '(' ;$^=')'^'[' ;$/=('`')| ( '.');$_='(' ^'}';$,='`'| (( '!'));$\=')'^'}';$:='.'^'~';#; =head1 リファレンス =head2 見た目のよいエンコーディング(Sightly Encoding) 見た目のよい文字セットには32文字あります: ! " # $ % & ' ( ) * + , - . / (33-47) : ; < = > ? @ (58-64) [ \ ] ^ _ ` (91-96) { | } ~ (123-126) I<見た目のよい文字列>は、この集合からひっぱられた文字だけで 構成されます。 C関数はASCII文字列(0-255)を見た目のよい文字列に 変換します;Cはその逆を行います。 =head2 関数リファレンス =over 4 =item ascii_to_sightly STRING ascii文字列STRINGを与えられ、見た目のよい文字列を返します。 =item sightly_to_ascii STRING 見た目のよい文字列STRINGを与えられ、ascii文字列を返します。 =item regex_print_sightly STRING ascii文字列STRINGを与えられ、見た目よくエンコードされ、 正規表現に埋め込まれたprintステートメントを持つPerlプログラム を返します。実行するとプログラムはSTRINGを出力します。 =item regex_eval_sightly STRING ascii文字列STRINGでPerlプログラムを与えられ、同等で、 正規表現に埋め込まれたevalステートメントを使う、 見た目よくエンコードされたPerlプログラムを返します。 =item clean_print_sightly STRING ascii文字列STRINGを与えられ、見た目よくエンコードされた、 evalを通して実行されるprintステートメントを持ったPerl プログラムを返します。 =item clean_eval_sightly STRING ascii文字列STRINGでPerlプログラムが与えられ、evalを通して 実行されるevalステートメントを使う、同等の、見た目よく エンコードされたPerlプログラムを返します。 =item regex_binmode_print_sightly STRING ascii文字列STRINGを与えられ、binmode(STDOUT)と正規表現に 埋め込まれたprintステートメントを持つ、見た目よくエンコード されたPerlプログラムを返します。実行するとSTRINGを出力します。 STRINGには0-255の範囲の任意の文字が入ることができることに 注意してください。この関数はバイナリ・ファイルを見た目よく エンコードするために使われます。この関数は、正規表現が バイナリのゼロのように見えないために安全ではありません; 代わりにCを使ってください。 =item clean_binmode_print_sightly STRING ascii文字列STRINGを与えられ、binmode(STDOUT)とevalを通して 実行されるprintステートメントを持つ、見た目よくエンコードされた Perlプログラムを返します。実行すると、プログラムはSTRINGを 出力します。 STRINGには0-255の範囲の任意の文字が入ることができることに 注意してください。この関数はバイナリ・ファイルを見た目よく エンコードするために使われます。 =item get_builtin_shapes 組込まれている形の名前を返します。 =item get_eye_shapes Iシェイプのリストを帰します。eyeシェイプは単に、F<.eye>という 拡張子を持ち、Fと同じディレクトリにあるファイルです。 =item border_shape SHAPESTRING GAP_LEFT GAP_RIGHT GAP_TOP GAP_BOTTOM WIDTH_LEFT WIDTH_RIGHT WIDTH_TOP WIDTH_BOTTOM 形の周りに枠線を引きます。 =item invert_shape SHAPESTRING 形を反転させます。 =item reflect_shape SHAPESTRING 形を鏡像にします。 =item reduce_shape SHAPESTRING FACT FACTの係数にしたがって形の大きさを縮小します。 =item expand_shape SHAPESTRING FACT FACTの係数にしたがって形の大きさを拡大します。 =item rotate_shape SHAPESTRING DEGREES RTYPE FLIP 時計回りに90、180、270度、形を回転させます。 RTYPE=0 大きな回転されられた形 RTYPE=1 小さな回転させられた形 RTYPE=2 つぶされて回転させられた形 FLIP=1 回転させることに加えて、形をひっくり返します(鏡像にします)。 RTYPE と FLIP は180度には適用されません。 =item pour_sightly SHAPESTRING PROGSTRING GAP RFILLVAR COMPACT 形を文字列SHAPESTRING、見た目よくエンコードされたプログラムを 文字列PROGSTRING、そして連続する形での空間(GAP)を与えられ、 適切に形が整えられたプログラム文字列を返します。RFILLVARは 埋草変数(filler variable)の配列へのリファレンスです。 埋草変数は2文字:C<$>と句読点文字、で構成される適切な Perl変数です。例えばRFILLVAR = C<[ '$:', '$^', '$~' ]>。 もしCOMPACTが1であれば、コンパクトな見た目のよいエンコーディングを 使います。0であれば、そのままの見た目のよいエンコーディングを 使います。 =item sightly HASHREF さまざまな属性について述べたハッシュ・リファレンスHASHREFが 与えられ、適切に整形されたプログラム文字列を返します。 HASHREFに入れることが出来る属性は以下の通りです: Shape あなたが欲しい図形を記述します。 最初に、組み込まれている形が探され、次に 'eye'シェイプ(EyeDrops.pmと同じディレクトリにある .eyeファイル)が探されます。最後にファイル名が 探されます。 ShapeString 欲しい図形を記述します。 この場合は図形の文字列を指定します。 SourceFile 変換されるソースファイル名 SourceString ファイル名の代わりに文字列を指定します。 BannerString 組込図形'banner'で使われる文字列 Regex ブール値。設定されると、ソースプログラムを 正規表現に埋め込もうとします。複雑なプログラムを 変換するとき、このフラグを設定しないでください。 Compact ブール値。設定されるとコンパクトな見た目のよいエンコーディングを使います。 Print ブール値。設定されると、デフォルトのevalステートメント の代わりにprintステートメントを使います。 (プログラムではなく)テキストファイルを変換するときには このフラグを設定してください。 Binary ブール値。エンコーディングがバイナリファイルであれば設定してください。 Gap 連続する図形の間での行数 Rotate 図形を時計回りに90、180、270度に回転します。 RotateType 0 = 大きく回転した図形 1 = 小さく回転した図形 2 = つぶされ、回転された図形 RotateFlip ブール値。図形を回転させ、さらにひっくり返し (反射)させたければ設定してください。 Reflect 図形を鏡像にします。 Reduce 図形の大きさを小さくします。 Expand 図形の大きさを大きくします。 Invert 図形を反転させます。 Indent 図形をインデントさせます。インデントするための空白の数。 BorderGap 図形の周りに枠線をつけます。枠線と図形との 隙間。 BorderGapLeft,BorderGapRight,BorderGapTop,BorderGapBottom 上記の1つまたは複数でBorderGapを上書きすることが できます。 BorderWidth 図形の周りに枠線をつけます。枠線の幅。 BorderWidthLeft,BorderWidthRight,BorderWidthTop,BorderWidthBottom 上記の1つまたは複数でBorderWidthを上書きすることが できます。 Width .eyeファイル図形では無視されます。組込図形では、 図形に対して適切に、典型的には図形の幅を文字数に 適切に解釈されます。図形が指定されないと、Width文字数の 長方形のブロックが生成されます。 TrapEvalDie ブール値。 生成されたプログラムに閉じた'die $@ if $@'を追加します。 evalコード・ブロックがdie関数を呼ぶとき、 プログラムはdieしません;代わりにdie文字列が$@でevalに 返されます。このフラグを使うことにより、dieを呼び出す プログラムdieを変換することが出来ます。 TrapWarn ブール値。 生成されたプログラムの前に'local $SIG{__WARN__}=sub{};'を 加えます。生成されたプログラムが警告を有効にして実行したとき 'No such signal: SIGHUP at ...'を吐き出すときに使用してください。 FillerVar 'filler variables'(埋草変数)もリストへのリファレンス。 埋草変数は$と句読点文字の2文字で構成されるPerl変数です。 例えば、FillerVar => [ '$:', '$^' ] =back =head2 図形の指定 以下のように図形を指定すると: sightly( { Shape => 'fred' ... まず組込のCという図形が探されます、そしてEyeDrops はFと 同じディレクトリでFファイルを探します。 もしShape属性でC<'/'> や C<'.'> を指定すると、代わりに、その名前を持つ ファイルが探されます。例えば: sightly( { Shape => '/tmp/fred.eye' ... 最後に文字列で図形を指定することもできます。例えば: my $shapestr = <<'FLAMING_OSTRICHES'; ##### ####################### FLAMING_OSTRICHES sightly ( { ShapeString => $shapestr ... ソースファイルなしに図形を指定すると: print sightly( { Shape => 'camel' } ); Iの埋め草が図形を埋めます。 図形無しにソースファイルを指定すると: print sightly( { SourceFile => 'helloworld.pl' } ); 図形がない、空白や改行がまったくない見た目のよい文字列が生成 されます。この文字列はWidth属性によって、固定幅の行に分解する ことができます: print sightly( { SourceFile => 'helloworld.pl', Width => 40 } ); 一般的には、I<組込>図形のWidth属性は指定するべきです。Width属性が F<.eye>ファイル図形では無視されることに注意してください。 =head2 図形リファレンス I<組込>図形には以下のものがあります: banner BannerString属性でのテキストの Linux banner コマンド (/usr/games/banner -w Width) srcbanner ソーステキストのLinux banner コマンド (/usr/games/banner -w Width) siertri シェルピンスキーの三角形 (2**Width 行) triangle 三角形(幅 Width 文字) このバージョンのEyeDropsで配布されるF<.eye>ファイル図形は以下の通りです: a "a"の水平方向のバナー acme オレンジ色が好きなPerl/Parrot Euro-hacker alien エイリアン (Ton Hospelだと噂されている, 1974年ごろの Roswell archivesより) bleach "use Acme::Bleach;"の垂直方向のバナー buffy "Buffy"の垂直方向のバナー buffy2 Buffyの天使のような顔 buffy3 ポニーに乗るBuffy buffy4 "Buffy"の水平方向のバナー camel ヒトコブラクダ (Camelus dromedarius, one hump) camel2 もう一つのヒトコブラクダ (use.perl.orgより) camel3 London.pmのロンドン動物園にいるフタコブラクダ coffee 一杯のコーヒー cricket このゲームではオーストラリアが世界チャンピオン damian Acmeという名前空間はすべて彼の失敗 dipsy テレタビットのディブシー (london.pmのinfobotの名前でもある) eugene Perl golferのチャンピオン, Eugene van der Pijll eye 目 gelly パリでのY::E 2003の各セッションでの呼び物の講演者 golfer 1番アイアンを打っているゴルファー japh JAPHはRandal L Schwartzによって1988年に発案されました jon 標準的な問題である白いコーヒーカップをホテルの壁にぶつけること により、Perl 6の開発を蹴り飛ばしてはじめさせました kermit カエルのカーミット larry Wall, Larry (Wall, RussであるRussell Wallとの対比 として) larry2 Ryan Kingによって寄稿されたLarryのマンガ llama ラマは一緒に繁殖することができるそれほどラクダと密接な 関係があります。(彼らの子供はcamaと呼ばれます) london 俳句 "A Day in The Life of a London Perl Monger" merlyn Just another Perl hacker, 別名 Randal L Schwartz mongers Perl Mongersのロゴ mosquito 蚊 naw 裸の腕相撲 (Y::E 2002, ミュンヘン) parrot 初めはエイプリルフールの冗談。冗談が冗談では なくなってしまった pgolf Perl Golfのロゴ (`/anickによって招かれた) pony "Pony"の水平方向のバナー pony2 ポニーの絵 riding "riding"の水平方向のバナー santa ゴルフをしているサンタ・クロース schwern 私のとても嫌なこと(=is my bitch) simon parrotの発案者 spoon 木で出来たスプーン tonick Ton Hospel と `/anicとのゴルフ・コンテストの 絵による表現;華やかだけどサンスペスにはならない tpr "The Perl Review"の垂直方向のバナー uml UMLダイアグラム undies 一組のパンツ window 窓 yanick `/anickの頭のマンガ yanick2 TPR02の間`/anickが口にしていたこと yanick3 yanick2の絵によるバージョン yanick4 図形yanickの省略したバージョン あなた独自の図形を作るのは簡単です。図形についてのアイデアは、 IあるいはIに検索エンジンを向けてください。 素晴らしい図形ができたら、EyeDropsの将来のバージョンに入れることが できるように送ってください。 =head1 バグ 一種類の文字を数多く持つ、本当に邪悪な図形は図形生成アルゴリズムを 台無しにするかもしれません。 変換されるプログラムが、正規表現とC<$_>の利用に注意している場合に のみ、全ての英数字を(Regex => 1によって)除去することが出来ます。 複雑なプログラムを変換するためには、Regex => 0を使わなければなりません。 それは前に見栄えのよくないCを吐き出します。 Regex => 1によって生成されたコードは実行するためにPerl 5.005以上を 要求します;前のバージョンで実行すると、エラーメッセージを見ることに なるでしょう: C。 変換されたプログラムは、Cの内側で走ります。 これは重大なプログラムで問題を起こすかもしれません。 例えばCステートメントあるいはCブロックは、トラブルを起こすかも しれません。もし絶望的であれば、CとC 属性を与え、実行し、その問題を修正するかどうかを見てください。 変換されるプログラムがPerlのフォーマット変数C<$:>、 C<$~> あるいは C<$^>を使っているならば、プログラムによって使われないPerl変数に 明示的にC属性を設定する必要があるかもしれません。 Linux Fは以下の文字をサポートしません: \ [ ] { } < > ^ _ | ~ Text::Bannerが拡張されているとき、それはLinux bannerコマンドの場所で 使われます。 =head1 作者(AUTHOR) Andrew Savige =head1 参考資料 Acmeの Y::E 2002 裸の腕相撲のムービー F. Perl Obfuscation Engines, for example, yaoe by Perl Monk mtve, at F and F. Perl Monks Obfuscationセクション、特に: F (Erudilのcamel code) そして F (Lenの Spiralling quine) そして F (シェルピンスキーの三角形). The definitive I reference is F. C<$|--> のイディオム ( I<宙返りするラクダ>のセクションで 利用される) は、このスレッドで "説明されて"います: F. L L L L =head1 クレジット(CREDITS) I blame Japhy and Ronald J Kimball and others on the fwp mailing list for exposing the ''=~ trick, Jas Nagra for explaining his C 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 I 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 I section. The C shape was derived from: F. Kudos to Elaine -HFB- Ashton for showing me this. =head1 著作権(=COPYRIGHT) Copyright (c) 2001-2002 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. =head1 翻訳 川合孝典(GCD00051@nifty.ne.jp)