Slide 1

Slide 1 text

Esoteric, Obfuscated, Artistic Programming in Ruby Yusuke Endoh (@mametter) Cookpad Inc. RubyConf 2017 (2017/11/17)

Slide 2

Slide 2 text

Yusuke Endoh (@mametter) • MRI committer • @ Cookpad Inc. – w/ @ko1 – Ko1: performance improvement – me: "Make Ruby programs robust"

Slide 3

Slide 3 text

My contributions for Ruby • The release manager for 2.0 • Implemented coverage.so, keyword arguments, etc. • OptCarrot: A NES emulator for Ruby3x3 benchmark • Branch coverage (Ruby 2.5) ↑OptCarrot . https://eregon.me/blog/2016/11/28/optcarrot.html http://engineering.appfolio.com/appfolio-engineering/2017/9/22/optcarrot-an-excellent-cpu-benchmark-for-ruby-3x3

Slide 4

Slide 4 text

Today's Topic: Ruby's power • "Ruby is easy to read and write"? – Incorrect • Ruby is just rich and flexible – Easy to write an easy-to-read code – Also, easy to write a hard-to-read code • I show you my bad examples – (Note: I'll talk about nothing useful)

Slide 5

Slide 5 text

Can you read? @_="_"=~/$/;_=@_+@_;$><<(""<<(_*_*_+@_)*_*_*_<< ((_+@_)*_*_*_+@_)*_*_+@_<<(((_+@_)*_*_+@_)*_+@_ )*_ *_ << ( ( (_+@_ )*_*_+ @_) * _+ + @_) * _*_ <<((((+ _+@_)*_ * _+ + +@_ )*_+@_)* _++ @_ )* _ ++@_ <<((_*_+@_ )*_ + + + @_)* _*_ <<_*_*_*_* _<< ( (_ * _ +@_) *_*_*_++@_ )*_<<(((_++@_)*_+@_)*_*_+@_)*_*_+@_<<((_+@_)*_* _*_*_ +@_)* _<<( ( (_+ +@_ )*_ ++ @_ ) *_+ @_) *_*_*_+ @_<< ( _* _ *_*_*_++ @_) *_+@_<< (((( _ ++ + +@_)* _*_ ++ @_ )* _ +@_)*_++ @_)*_ +@_<< (((( _+ + @_)*_*_+ @_)*_+@_)*_+@_)*_<<(((_+@_)*_*_*_+@_)*_+@_)*_<< _*_*_*_*_+@_<<(_*_+@_)*_)#_$`/^|:()[_-|?|_||:`/

Slide 6

Slide 6 text

Can you read? @_="_"=~/$/;_=@_+@_;$><<(""<<(_*_*_+@_)*_*_*_<< ((_+@_)*_*_*_+@_)*_*_+@_<<(((_+@_)*_*_+@_)*_+@_ )*_ *_ << ( ( (_+@_ )*_*_+ @_) * _+ + @_) * _*_ <<((((+ _+@_)*_ * _+ + +@_ )*_+@_)* _++ @_ )* _ ++@_ <<((_*_+@_ )*_ + + + @_)* _*_ <<_*_*_*_* _<< ( (_ * _ +@_) *_*_*_++@_ )*_<<(((_++@_)*_+@_)*_*_+@_)*_*_+@_<<((_+@_)*_* _*_*_ +@_)* _<<( ( (_+ +@_ )*_ ++ @_ ) *_+ @_) *_*_*_+ @_<< ( _* _ *_*_*_++ @_) *_+@_<< (((( _ ++ + +@_)* _*_ ++ @_ )* _ +@_)*_++ @_)*_ +@_<< (((( _+ + @_)*_*_+ @_)*_+@_)*_+@_)*_<<(((_+@_)*_*_*_+@_)*_+@_)*_<< _*_*_*_*_+@_<<(_*_+@_)*_)#_$`/^|:()[_-|?|_||:`/

Slide 7

Slide 7 text

Demo • "Hello, RubyConf!" program written using only symbol characters $ ruby symbols.rb Hello, RubyConf! $

Slide 8

Slide 8 text

Spoiler • If you want to read it yourself… • Three key techniques – How to make a number (by only symbols) – How to make a string (by only symbols) – How to print a string (by only symbols)

Slide 9

Slide 9 text

Spoiler: How to make a number • String#=~ returns the beginning index of matched substring • Calculation to make a large number "Hello, RubyConf!" by Symbols "@" =~ /$/ #=> 1 "@@" =~ /$/ #=> 2 "@@@" =~ /$/ #=> 3 _ = ("@@"=~/$/) # assigns 2 to _ _*_*_*_ #=> 16

Slide 10

Slide 10 text

Spoiler: How to make a string • String#<< treats an integer as a codepoint (ASCII code) "Hello, RubyConf!" by Symbols "" << 72 << 101 << 108 << 108 << 111 #=> "Hello"

Slide 11

Slide 11 text

Spoiler: How to print a string • $> is $stdout • IO#<< writes its argument to the IO "Hello, RubyConf!" by Symbols $> << "Hello"

Slide 12

Slide 12 text

Spoiler: Use All Techniques $> << "Hi" $> << ("" << 72 << 105) __ = "_"=~/$/ _ = "__"=~/$/ $> << ("" << (_*_*_+__)*_*_*_ << ((_+__)*_*_+__)*_*_*_+__) 1 2 72 105 "Hello, RubyConf!" by Symbols

Slide 13

Slide 13 text

Spoiler: More Complex Code? • Q. Can we write a more complex code than "Hello, world!"? • A. Yes! There is a great idiom to call "eval" by using only symbols • Exercise: Explain how it works ->(&_){ _["", "eval", ""] }[&:"#{ "send" }"] "Hello, RubyConf!" by Symbols Replace them by using the previous techniques

Slide 14

Slide 14 text

Question 2: Can you read? 90-line code by only alphabets! begin begin begin public begin begin def each clear rescue begin begin begin end end end concat begin dup ensure concat begin clear concat concat concat concat concat concat size concat begin begin begin size end end end begin size end ensure begin clear end end end concat begin dup ensure concat begin clear begin concat concat size end until hex concat concat concat concat begin size end concat concat begin size end rescue upcase begin concat begin concat size end end begin size end ensure begin clear end end end concat begin dup ensure concat begin clear concat begin concat size end unless begin end begin concat concat concat begin size end end begin begin concat concat size end end concat begin concat begin size end end concat concat begin size end unless begin end begin size end ensure begin clear end end end concat begin dup ensure concat begin clear concat concat begin begin size end end concat concat concat size unless begin end concat begin concat size end if downcase begin concat concat size end rescue upcase concat begin concat size end unless begin end concat begin begin begin size end end end begin size end ensure begin clear end end end concat begin dup ensure concat begin clear concat concat concat concat concat concat size begin concat concat size end rescue upcase concat size if downcase rescue upcase begin size end ensure begin clear end end end concat begin dup ensure concat begin clear begin concat concat begin size end end begin concat concat size end unless begin end concat concat begin begin size end end concat concat begin concat concat size end begin begin concat size end end if downcase begin size end ensure begin clear end end end concat begin dup ensure concat begin clear begin concat begin concat size end end concat concat concat concat concat size begin concat concat size end rescue upcase begin size end ensure begin clear end end end concat begin dup ensure concat begin clear concat concat begin size end if downcase begin begin concat concat size end end concat concat concat size rescue upcase concat concat concat size rescue upcase begin concat begin size end end rescue upcase begin size end ensure begin clear end end end concat begin dup ensure concat begin clear concat concat concat size rescue upcase concat concat concat begin concat size end concat begin concat begin size end end begin size end ensure begin clear end end end concat begin dup ensure concat begin clear concat concat concat concat concat concat size begin size end ensure begin clear end end end concat begin dup ensure concat begin clear begin concat begin concat concat size end end concat concat begin size end unless begin end concat concat concat size unless begin end begin size end ensure begin clear end end end concat begin dup ensure concat begin clear concat concat begin size end rescue upcase begin begin concat concat concat size end end concat begin concat size end unless begin end concat begin concat begin size end end begin begin concat concat size end end begin begin concat size end end rescue upcase begin size end ensure begin clear end end end concat begin dup ensure concat begin clear concat begin concat size end rescue upcase concat begin concat begin concat size end end begin concat concat size end unless begin end concat concat begin begin concat size end end begin size end ensure begin clear end end end begin begin prepend begin chr end end end concat begin dup ensure concat begin clear begin concat concat begin size end end concat begin concat concat concat size end begin concat concat concat begin size end end begin concat begin size end end if downcase begin size end ensure begin clear end end end puts concat begin dup ensure concat begin clear concat begin concat concat concat size end concat begin concat concat concat size end size ensure clear end end end end end end for each in begin inspect end do end end end begin begin begin public begin begin def each clear rescue begin begin begin end end end concat begin dup ensure concat begin clear concat concat concat concat concat concat size concat begin begin begin size end end end begin size end ensure begin clear end end end concat begin dup ensure concat begin clear begin concat concat size end until hex concat concat concat concat begin size end concat concat begin size end rescue upcase begin concat begin concat size end end begin size end ensure begin clear end end end concat begin dup ensure concat begin clear concat begin concat size end unless begin end

Slide 15

Slide 15 text

Demo • "Hello, RubyConf!" program written using only alphabets $ ruby alphabets.rb Hello, RubyConf! $

Slide 16

Slide 16 text

Spoiler: Basic Structure "Hello, RubyConf!" by Alphabets s = inspect #=> "main" s.clear s.concat 72 #=> add 'H' s.concat 105 #=> add 'i' puts s Need to remove the periods

Slide 17

Slide 17 text

class String def foo self.clear self.concat 72 #=> add 'H' self.concat 105 #=> add 'i' puts self end end inspect.foo Spoiler: Abuse Open Class "Hello, RubyConf!" by Alphabets We can omit "self." ! Need to remove the period

Slide 18

Slide 18 text

class String def each clear concat 72 #=> add 'H' concat 105 #=> add 'i' puts self end end for x in inspect do end Spoiler: Abuse "for"-statement "Hello, RubyConf!" by Alphabets Equivalent to inspect.each {} Exercise: Remove the numbers and the upper-case letter Got "Hi" program By only alnums!

Slide 19

Slide 19 text

Frequently Asked Question • Q. Why do I write such a program? • A. Because it's there. – To figure out Ruby's power and its limit – To stress the interpreter with unusual code • Q. What inspired me? • A. Esoteric programming languages – Funny joke languages including Brainf*ck and Chef

Slide 20

Slide 20 text

Brainf*ck • A language using only eight symbols – Inspired me to create "Hello by Symbols" +++++++++[>++++++++>+++++++++++>+++++<<< ]>.>++.+++++++..+++. >-.------------.<++ ++++++.---- ----.+++.------.--------.>+. Hello, world! in Brainf*ck Examples of Esolangs

Slide 21

Slide 21 text

Chef (not a provisioning tool) • A language where programs look like cooking recipes Cheese cake in Chef. Ingredients. 100 g cream cheese 97 g sour cream *snip* Method. Put the cream cheese into the mixing bowl. Put the sour cream into the mixing bowl. *snip* Examples of Esolangs Data section Code section

Slide 22

Slide 22 text

[PR] Cookpad • One of the world's largest recipe sharing platform • My Cheesecake recipe is published at Cookpad – https://cookpad.com/us/ recipes/3335222 – It is a program in Chef • Prints "cookpad" – It can be also used as a real recipe • Chef (and some esolangs) inspired me to create a funny-shaped Ruby code…

Slide 23

Slide 23 text

Can you read? v=0000;eval$s=%q~d=%!^LcfYoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_>

Slide 24

Slide 24 text

Demo $ cat qlobe.rb v=0000;eval$s=%q~d=%!^LcfYoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "###%.#% ::" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC ".#####%.#% " 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "#% .#####%." 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "####% .####" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "#######% .#" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC ":::#######%" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "% :::#####" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_>

Slide 25

Slide 25 text

Qlobe: A Quine with Spinning Globe v=0055;eval$s=%q~d=%!^LcfYoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "% :::#####" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC ":::#######%" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "#######% .#" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "####% .####" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "#% .#####%." 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC ".#####%.#% " 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "###%.#% ::" 97N-A&Kj_K_>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_>

Slide 26

Slide 26 text

Spoiler: Two key techniques • Quine: self-reproducing program • ASCII-art programs – Ruby's %-notation works great for them

Slide 27

Slide 27 text

Spoiler: Quine • A program that prints its source code • Basic structure eval s=%q( s="eval s=%q(#{s})" # Do funny thing here! # e.g., Rotate the globe in the string puts s ) Qlobe: A Quine with Spinning Globe Reconstruct the original code as a string Print it

Slide 28

Slide 28 text

Spoiler: ASCII-art code • Write a code with no space and backslash • Wrap it with "eval(%w(" and ").join)" • You can shape your code as you like puts"Hello,world!" eval(%w(puts"Hello,world!").join) eval(%w(pu ls "H el lo ,w or ld!")*"")# #=> Hello,world!

Slide 29

Slide 29 text

Quine-relay eval$s=%q(eval(%w(B=92.chr;g=32.chr;puts(eval(%q(N=10.chr;n=0;e=->s{Q[Q[s,B],?"].K(N,B+?n)};E=->s{'("'+e[s]+'")'};d=->s,t=?"{s.K(t){t+t}};def~f(s,n)s.K(/.{1,#{n*255}}/m){yield$S=E[$s=$&]}end;Q=->s,t=?${s.K(t){B+$&}};R=";return~0;";V=-> s,a,z{s.K(/(#{B*4})+/){a+"#{$&.size/2}"+z}};C=%w(System.Console~Write);$C=C*?.;$D="program~QR";$G="~contents~of"+$F="~the~mix!g~bowl";$L="public~static";rp=->s,r{v="";[r.!ject(s){|s,j|o={};m=n=0;s.size.times{|i|o[f=s[i,2]]||=0;c=o[f]+= 1;m(p(3+ord~c);Z"-1~0~";c))#{E[%(puts~"#{Q[e[%(echo~'a::=`x7e#{Q[Q["let~s=#{E["!t~mX{Z#{d[E[%(module~QR;!itial~beg!~#{f("let~s=#{ E[%(Module~QR:Sub~MX:Dim~s,n,i,c~As~Object:n=Chr(10):For~Each~c~!"#{d["<#{U="xsl:template"}~match='/'><`x21[CDATA[#{%(sub~f(s$,n)Z(s$);:for~i=1to~n~Z("Y");:next:end~sub:f("#{V[e[%(H,format="#{y="";f("^H{-}{txt}{#{Q["echo~-E~$'#{Q[Q[E[%(with~Ada.Text_Io;procedure~qr~is~beg!~Ada.Text_Io.Put("#{d[% (!terp:library"afnix-sio"`ntrans~O(n){trans~o(afnix:sio:OutputTerm)`no:H(Byte(+~128~n))}`ntrans~f(v~n){`nO(+(/~n~64)107)`nO(n:mod~64)`nO~v}`ntrans~D(n){if(<~n~4){f(+(*~6~n)9)48}{if(n:odd-p){D(-~n~3)`nf~27~48`nf~36~11}{D(/~n~2)`nf~21~48 `nf~48~20}}}`ntrans~S"#{e[%W[STRINGz:=~226+~153,a:=z+~16 6,b:=a+"2 "+z+~160,c:=b+"8"+z+~165,t:="#!clude"+~(10)+"!t"+~(32)+"mX{puts#{d[E[%(class~QR{#$L~void~ma!(SJ[]v){System.out.Z(#{E["H('#{Q[e["implement~ma!0()=Z"+E["BEGIN{ Z#{E[%(echo~'#{%(f(s){System.out.Z(s);}s="389 **6+44 *6+0 0p45*,"; for(c:#{E[(s="#!clude`n!t~mX{std::cout<<#{E[%(class~Program{#$L~void~MX{#$C("Qu!e~Relay~Coffee.^n^nIngredients.^n");for(!t~i=9;i++<126;)#$C($"{i}~ g~caffe!e~{i}^n");#$C("^nMethod.^n");foreac h(c h ar~c~!#{E[%((doseq[s(lazy-cat["IDENTIFICATION~DIVISION.""PROGRAM-ID.~QR.""PROCEDURE~ DIVISION."'DISPLA`x59](map~#(str"~~~~^""(.replace~%1"^""" ^"^"")"^"&")(re-seq~#".{1,45}""#{e["(f=(n )- >Array(n+1).jo!~'Y');console.log('%s',#{V[E[%((H-l!e"#{e["impor t~std.stdio;void~mX{H(`x60#{%(method~MX{Z(@"#{d[" [#{%(class~QR:Application{void~f(SJ~con st~s,!t~n){for(Pr!t(s);n;n--)Pr!t("Y");}void~MX{#{f("IO.puts "+E[%((pr!c~"#{e["`nma!(_)->`nio:fH#{d[E['Zf n("""'+d[?"+"%option~noyywrap`n%%`n%%` n!t~mX{puts#{E["echo~'#{Q[Q[%(~:~A~."#{g*9}"~;~:~ B~A~."~WRITE(*,*)'"~A~;~:~C~B~T`x59PE~." ~'"~CR~;~:~D~S"~#$D"~C~S^"~Z~^"(&"~C~ S^"~#{e[%(Z"#{e["s:=OutputTextUser();Write All(s,#{E[%(Zf"#{e[d[f('set~Z"-";Z'+E [%(package~ma!;import"fmt";func~mX{ fmt.Pr!t#{E[%(236:j;{119:i;{206i-:i;.48<{ 71+}{[i]^48-*}if}%}:t;"algoritmo~Q R;!"[195][173]++'cio~imprima("'"0 1314 1"t"/12131"t~6*"/1:1918151:??62714 13/4=3626612/2 /353251215/`x5a0`x5a0R"t"#{e[%( show~"z=new~java.util.zip.G`x5aI POutp utStream(System.out);z.H('#{ "ma!=putStr"+E["class~QR{#$L ~function~mX{neko.Lib.Z#{E[%(p rocedure~mX;i:=c:=0;s:=#{E[%(.c lass ~public~QR`n.super~#{$T="ja va/io/Pr!tStream"}`n.method~#$L~ma!([L #{S="java/lang/S"}J;)V~;]`n. limit~stack~2`ngetstatic~#{S}ys tem/out~L#$T;`nldc~"#{ e[%(class~QR{#$L~void~ ma!(SJ[]v){SJ~c[]=new~SJ[99999],y="",z=y,s=" #{z=t=(0..r=q=126).map{|n| [n,[]]};a="";b=->n{a<<(n%78+55) %84+ 42};(%(P={0:'[+[]]',m:'((+[])'+(C= "['constructor']" )+"+[])['11']"};for(R~!~B=('`x21[]@`x21`x21[]@[][[ ]]@'+(A="[]['fill']")+"@( []+[])['fontcolor']([])@(+('11e20 ')+[])['split']([])@"+A+C+"('return~escape')()("+ A+')').split( '@'))for(E~!~D=eval(G='('+B[R]+'+[])'))P[T=D[E]]=P[T]| |G+"['"+E+"']";for(G='[ ',B=0;++B<36;)P[D=B.toSJ(36)]= B<10?(G+='+`x21+[]')+']':P[D]||"(+('"+B+"'))['to'+( []+[])"+C+"[ 'name']]('36')";A+=C+"('console.log(unescape(^"";for(E~!~G =#{E[%(A=Z;A("echo~'k` x60");[(A("`x60`x60s"`x5e8* "i");for~j=6:-1:0;x=(Int(c)>>j)%2+1;A("`x60"*"kki"[x:x+1 ])end)fo r~c~!~jo!(["Section`x48eader+name:=QR;SectionPublic-ma!<-(";[ "^"$(replace(replace( s,"Y","YY"),"^"","Y^""))^" .Z;"for~s=matchall(r".{1,99}",#{Q[E["console.log"+Q[E[%(@s=g loba l[#{i=(s=%(`x48AI~1.2`nVISIBLE~"#{"x=sJ.K(#{V[E["changequote(<@,@ >)`ndef!e(p,<@#{"all :`n`t@echo~'#{d["l!el:99 999;Z#{E["solve~satisfy;output~[#{E[%(.assembly~t{}.method~#$L~ vo id~MX{.entrypo!t~ldstr"#{e["m{{`x21:~x`nqr:~|-`n~:db`x60#{e[s="$Z#{E[%(#!clude< stdio.h>`nmodule~QR{ }implementation{!t~mX_ _attribute__((C,spontaneous)){puts#{E["Zf#{E["echo"+E["#import#{ N}!t~mX{puts#{E["Z_sJ"+E["s=toascii#{E["Z#{E["$console:l!e[#{"# $D(output);beg!~H(# {f((p="eval";%($_="#{ s,v=rp["$_='#{Q[%($z)&&$i/$z<($c<$w?ord($s[(!t)( $c/3)]):$c--%3+2)? $t[2].$t[$c%3%2].$ t[$c%3]:"^0^0^0":"^0")$c=$i%$z;foreach(array("I`x48DR".pack("NNCV",$w+2,128,8,2 ),"IDAT".gzcompress($m),"IEND")as$ d)echo~pack("NA*N ",strlen($d)-4,$d, crc32($d));).K(B,"`x7f"),?']}';s:g/^x7f/Y/;Z~$_",128..287];s="$_='#{Q[s,c=/['Y]/ ]}';$n=32;$s='#{Q[v,c]}';$s=`x7 es{..}{$a=$&;$b=c hr(--$n&255);`x7e s/$b/$a/g;}eg;Z";(s+N*(-s.size%6)).unpack("B*")[0].K(/.{6}/){n=$&.to_i~2;((n+14)/2 6*6+n+47).chr}}";s|.|$n=ord $&;substr~unpack( B8,chr$n-!t($n/32 )*6-41),2|eg;eval~pack'B*',$_).scan(/[~,-:A-z]+|(.)/){p="s++#{$1?"chr~#{$1.ord}+e": $&+?+};"+p};p),1){"'#$s' ,"}}'')end.".K(/[: ;()]/){?`x5e+$&}} ]"]};quit"]};t=num2cell(b=11-ceil(s/13));for~n=1:9m={};for~i=1:141f=@(x,y,n)repmat ( ['Ook'~char(x)~'~Ook' ~char(y)~'~'],[1~a bs(n)]);m(i)=[f(z =46,63,n)~f(q=z-(i<13)*13,q,i-13)~f(33,z,1)~f(63,z,n)];end;t(x)=m(diff([0~s(x=b= =n )])+13);en d;Zf ('%%s',t{:})"]]+R} }"]]}`n"]};return~ 0;}~})]};"]}`x60` n~global~_start`n~_start:mov~edx,#{s.size}`n~mov~ecx,m`n~mov~ebx,1`n~mov~eax,4` n ~!t~128`n~mov ~ebx,0`n~mo v~eax,1`n~!t~12 8`nx:~|`n~}}{{{qr}} }"]}"call~void~[ms corlib]#{C*"::"}(sJ)ret})]}];"]};quit();",?$].K(?'){"'^''"}}'"}@>)`np"],?&,?& ] },'&(%d+)&',fu nction(s)retur n~sJ. rep('Y',tonu mber(s))end);Z(x)". K(/[:"]/,":^0")}"` n`x4bT`x48`x58B`x59E~B`x59E)).size+1}x~i8]c"#{s.K(/[^"`n`t]/){"^%02`x58"%$ &. ord}}^00"declare~i32@puts(i8*)d ef!e~i32@mX{ %1=call~i 32@puts(i8*getelemen tptr([#{i}x~i8],[#{ i}x~i8]*@s,i32~0,i32~0))ret~i32~0})],?#]]]})];");"],"^n")];[for~i=0:2:4; x=(( Int(c)%83-10)>>i)%4+1;A("ski`x60 "[x:x])end~for~c ~!"AG- `x48-`x48Fy.IlD==;=jd lAy=;=jldltldltl{lAu lAy=jtlldlAyFy=?=jdlAyGFyFyG2AFy>zlAFFBCjldGyGFy>GFy.AGy=G==n`x48==nl ldC=j@=j tlldltldlAut11"];A("'"))]})A+="' +`x21[]+'"+G.charCo deA t(E).toSJ(16);for(A+=" ^".replace(/'+`x21[] +'/g,^"%^")))')()",R=0;R<9;R++)A=A.replace(/'.*?'/g,function(B){T= [];for(E=1 ;B[E+1];)T.push(P[B[E++]]);return~T.jo!('+')});conso l e.log('"'+A+'"'))).byte s{|n|r,z=z[n]||(b[r/7 8];b[r];q<6083&&z[n]=[q+=1,[]];t[n])};b[r/78];b[r]}";!t~i=0,n=0 ,q=0;for(;++n< 126;)c[n]=""+(char)n;for(;i<#{a.size};){q=q*78+(s .charAt(i)-13)%84;if(i++ %2>0){y=qn{L<<(n+62) %92+35;D};s.bytes{|c|n>0?n-=1:(t[c]=(t[c]||[]).reject{|j| j4&&x<<[k,j]};x=x. max)?(n,j=x;x=b.size;(u=[x,3999].m!;D[u%87][u/87];L<0;x=4001+i-j;D[x%87][x/87][n-5] ):b<`nchar*p=#{E [L]},s[999999],*q=s;!t~mX{!t~n,m;for(;*p;){n=(*p-5)%92+(p[1]-5)%92*87;p+=2;if(n >3999)for(m=(*p++-5)%92+6;m--;q++)*q=q[4000-n];else~for( ;n--;)*q++=*p++;}puts(s)#{R}}")]}){s+="00g,";for(m=1;m<256;m*=2)s+="00g,4,:"+(c/m%2>0?"4+":"")+",";f(s);s="4,:,";}f(s+s);for(c:Base64.getDecoder().decode("kaARERE`x58/I0ALn3n5ef6l/Pz8+fnz58/BOf5/7/hE`x58/O`x5azM5mC`x58/Oczm`x5azBPn5+`x 58/OczMznBL/nM5m`x5azBPu++fPPOc5zngnnO`x5azO`x5agnBMGAW7A==")){c=c<0?256+c:c;for(i=0;i++<3;c/=8)f(c%8);f("8*+8*+,");}f("@");).K(?',%('"'"'))}'|sed~-e's/Y/YY/g'~-e's/"/Yq/g'~-e's/.*/Z~"&"^nquit/')]}}"]],?']}');".K(B,?`x5e)]}.replace("`x 5e","Y"));}})]]};}";FORiTO`~UPBtDO`~INTn:=ABSt[i];Z(~(50+n%64)+c+~(50+n%8MOD8)+c+~(50+nMOD8)+b+"`x4a"+a)OD]*"REPR"]}"`ntrans~c~0`ndo{D(Integer(S:get~c))`nf~35~39}(<(c:++)(S:length))`nf~24~149)].K(N,'"&Character'+?'+'Val(10)&"')}");end; )]+"`nsys.exit~0",B],?']}'",/[^{}]/]}}",35){y<<",`n"+$S;"%s"}}")+y],'",','):f("']}",0))}]]>#{U}>"].K~N,'"&~VbLf~&"'}":s="~~~":For~i=0To~7:s~&=Chr(32-(Asc(c)>>7-i~And~1)*23):Next:#$C(s~&n~&Chr(9)&n~&"~~"):Next:#$C(n~&n~&n): End~Sub:End~Module)]}`nput=s`nZ`nqa`x21",3){%($H("%s",#$S);)+N}}end~endmodule)],?%]+R}}"]},i=0,t='k';while(s[i])t='^x60.'+s[i++]+t;console.log(t)",B],?`x21].K(?',%('"'"'))}'"^n::=^na")],/[`[`]$]/]}")]};Z"0~0~-1";)],?']}';cr",127..255]; f(%(variable~s=`x60#{s.K(/.{1,234}/){$&.K("`x60",%(`x60+"`x60"+`x60))+"`x60+`n`x60"}}`x60,i;for(i=0;i<129;i++)s=strreplace(s,pack("C",255-i),substrbytes(`x60#{v[0,99]}`x60+`n`x60#{v[99..-1]}`x60,i*2+1,2));Zf("%s",s)),7){"f('%s')`n"%$s. unpack("`x48*")}}Zf("^n#[Exeunt]");quit)]}")),196){%(Z#$S;)}}}"]});})).gsub(/[!HJKXYZ^`~]/){[B*2,:write,B,:tring,:gsub,"ain()",B*4,:print,g,:in][$&.ord%47%12]})))*"")#_buffer_for_future_bug_fixes_#_buffer_for_future_bug_fixes_#_buffer_ ############################################################################## Quine Relay -- Copyright (c) 2013, 2014 Yusuke Endoh (@mametter), @hirekoke #############################################################################) Demo: https://travis-ci.org/mame/quine-relay

Slide 30

Slide 30 text

Quine-relay • A Ruby code • that generates Rust code • that generates Scala code • … • that generates REXX code • that generates the original Ruby code 128 languages involved in total

Slide 31

Slide 31 text

Quine-relay • A Ruby code • that generates Rust code • that generates Scala code • … • that generates REXX code • that generates the original Ruby code 128 languages involved in total

Slide 32

Slide 32 text

Spoiler: Quine-relay eval s=%q( s=%(eval s=%q(#{s})) # Generate a REXX code that prints it # … # Generate a Scala code that prints it # Generate a Rust code that prints it puts s )

Slide 33

Slide 33 text

Monumental Quine A column object 3D model data Ruby code is inscribed You can buy it at Shapeways! https://www.shapeways.com/shops/mametter Execute the code 3D printer

Slide 34

Slide 34 text

Spoiler: Monumental Quine eval s=%q( s=%(eval s=%q(#{s})) # Generate 3D model data that # embeds the string puts s ) +TrueType font data +Font renderer +Code golf

Slide 35

Slide 35 text

Radiation-hardened Quine eval=eval=eval='eval$s=%q(eval(%w(puts((%q(eval=ev al=eval=^Z^##^_/#{eval@eval@if@eval)+?@*10+%(.size >#{(s=%(eval$s=%q(#$s)#)).size-1}}}#LMNOPQRS_##thx .flagitious!## )+?@*12+%(TUVW XY/.i@rescue## /_3141592653 589793+)+?@* 16+%(+271828 182845904; _987654321 0;;eval)+? @*18+%("x =((#{s.s um}-eval. _sum)%256 ).chr; ;eval)+?@ *12+%(.s can(//){ a=$`+x+$ ^_a.unpa ck (^ H*^)[0]. hex%999989==#{s.unpac k("H*")[0].hex%999989 }&&eval(a)}#"##"_eval @eval####@(C)@Copyrig ht@2014@Yusuke@Endoh@# ###)).tr("@_^",32.chr< <10<<39).sub(?Z,s));e xit#AB CDEFGHIJK)*%()))#'##' /#{eval eval if eval .size>692}}#LMNOPQRS ##thx.flagitious!## TUVWXY/.i rescue##/ 3141592653589793+ +271828182845904; 9876543210;;eval "x=((42737-eval. sum)%256).chr;;eval .scan(//){a=$`+x+$' a.unpack('H*')[0].hex%999989==68042&&eval(a)}#"##" eval eval#### (C) Copyright 2014 Yusuke Endoh ####

Slide 36

Slide 36 text

Demo • Works as an ordinary Quine $ ruby rquine.rb > rquine2.rb $ diff –s rquine.rb rquine2.rb rquine.rb and rquine2.rb are identical

Slide 37

Slide 37 text

Radiation deletes any one letter... eval=eval=eval='eval$s=%q(eval(%w(puts((%q(eval=ev al=eval=^Z^##^_/#{eval@eval@if@eval)+?@*10+%(.size >#{(s=%(eval$s=%q(#$s)#)).size-1}}}#LMNOPQRS_##thx .flagitious!## )+?@*12+%(TUVW XY/.i@escue## /_3141592653 589793+)+?@* 16+%(+271828 182845904; _987654321 0;;eval)+? @*18+%("x =((#{s.s um}-eval. _sum)%256 ).chr; ;eval)+?@ *12+%(.s can(//){ a=$`+x+$ ^_a.unpa ck (^ H*^)[0]. hex%999989==#{s.unpac k("H*")[0].hex%999989 }&&eval(a)}#"##"_eval @eval####@(C)@Copyrig ht@2014@Yusuke@Endoh@# ###)).tr("@_^",32.chr< <10<<39).sub(?Z,s));e xit#AB CDEFGHIJK)*%()))#'##' /#{eval eval if eval .size>692}}#LMNOPQRS ##thx.flagitious!## TUVWXY/.i rescue##/ 3141592653589793+ +271828182845904; 9876543210;;eval "x=((42737-eval. sum)%256).chr;;eval .scan(//){a=$`+x+$' a.unpack('H*')[0].hex%999989==68042&&eval(a)}#"##" eval eval#### (C) Copyright 2014 Yusuke Endoh #### r

Slide 38

Slide 38 text

Demo • You can delete any one character • It automatically restore itself! $ ruby broken.rb > rquine2.rb $ diff –s rquine.rb rquine2.rb rquine.rb and rquine2.rb are identical

Slide 39

Slide 39 text

Spoiler: Radiation-hardened Quine • Redundancy-based error-correction – The longer one is always not broken • When a letter out of "" is deleted, what should we do? x = "" y = "" eval [x, y].max_by {|s| s.size }

Slide 40

Slide 40 text

Spoiler: Radiation-hardened Quine • A style against one-letter deletion • Even if one letter is deleted, this code successfully does one of the following: – Assign the string like "" to a variable eval – Call eval to "" and exit • Note: Cookpad's service is robust, but its source code is not so bad like this x = "" eval=eval=eval="(;exit)#"##" rewrite

Slide 41

Slide 41 text

More? Buy my book! • "The World of Obfuscated, Esoteric, Artistic Programming" – Contains about 40 codes like this talk – Written in Japanese

Slide 42

Slide 42 text

Related work • International Obfuscated C Code Contest (IOCCC) – A programming contest for hard-to-read programs written in C language • Transcendental Ruby Imbroglio Contest for rubyKaigi (TRICK) – The judges (including I) held TRICK twice • https://github.com/tric/trick2013 • https://github.com/tric/trick2015 – TRICK FINAL will be held in RubyKaigi 2018 • Please send your esoteric Ruby code to us! • https://github.com/tric/trick2018

Slide 43

Slide 43 text

Conclusion • Ruby is very rich and flexible language – You can use Ruby with broken keyboards (only symbols, or only alphabets) – You can write artistic and super-robust Quine in Ruby • One more thing…

Slide 44

Slide 44 text

A Quine that takes five minutes 0;BEGIN{eval(s=%q~s=s.gsub(/¥e¥[¥d+m/,"");eval((%w¥C="0;BEGIN{eval(s=%q#{126.chr+s+126.chr})}";E="" ;Z=32.chr;D=->k,d{c=35;k.scan(/../){c+=1;d.gsub!(c.chr,$&)};d};include(Math);M=D["PPQPQi^heigMk=nis iJO^L^MjQqiEPQjQn^ikjviKNfihhvLFPOLQOPQoiOijd]igiljkMmihjkiQQNNiQiPjiiilihi","^kNojsdhm.;vA.;/7ciqL ^A;;.vA5k&jjBhohdvPkhd^lNQE(m3:v0:vjlHkhdjGhHN:HjOHj6Bim1HBgn*-INBinJPNvdjnBfnPO3gGhkO%NBhn>INvdlnB cl@lkldclJij7jjBjm(:PHqdcnBjoN@eLNHOehI+H4hFE3h>H3h+92rhD92jhGbi6Orh?i0oh>H4hQG2f&GHOohJi0rhPD6P'QD EIv&92'I_K/8P8Q8P818Q8QK,9D1NQNDKKK1KQNGK8DKKKG)QciDkA@9^,G^AmM;Q@/?;OI^=P7FQ/?vM?.%vM?.,9bL%;OI5lh `,_CI]A]LCGCDCNC@C]MCNCNC5CG]L]ACkk]PD*PF&h6Omhgj

<'6Pgh6OJ$I)Q:2fhgjP<<(IlhE4hfj$F7gL>%Jo=@eM<-mLOJ>-mLOfMGoM>7fM(rA5 kAkOdjm7`9)fM5G+IsMf=4L1GgL4if=G+:_D*-I^$-J•i]"].bytes;F=44100;z={};H=->n,l,v{z[[n,l,v]]||=(l=(3e5/ l).round;t=0.0;(0...l).map{|j|k=(j+1000)%l/1000.0;x=j*440*2**(n/12.0)/F*PI;sin(x+2*t=sin(x+t))*v*(k >4?1:(2-(3-k).abs).abs)/3})};W="MHJEFAFH".bytes.flat_map{|n|H[n-84,6,30]}*29+H[-7,3,30];i=n=v=0;l=6 ;(c=M.pop-98;c<0?v=c*5+55:(l=l*12/(2**(c%5)*3**(c/5));d=M.pop-93;d>0&&(j=i;H[n+=d-13,l,v].map{|t|W[ j]+=t;W[j+4e5]+=t;W[ j+8e5]+=t;j+ =1 }); i+ =3e 5/l)) while (M!=[]);Y=["data",W. size,*W.map{ | n|n +1 28} ].pa c k("A4VC *");o=IO.popen("apla y"+Z+"-q"+Z+?-, " wb" ); o<<["R IFF",28+Y .size,"WAVEfmt"+Z,16 ,1,1,F,F,1, 8]. pac k( "A4V A8VvvVVvv ")<EI GAIJIaiaDDFFFkaq j J ff EJjja|qqEa Gb ppJa H H| |kkbbI IJJaa","J gGG2i66,Cg2C2i3 ;& Jd e Hde,;Cj&D+A-$?,C;H<=I?DHJA-$@@=F@@kEka8?a<1@=8q=8qa&>=?4A4 $=a @?J@ <<= %? I=a1|f 'a =%EGJAii2c3;7:;JqF@;J?ka?/;Cq7:?'?'a?%nm|hh >j):0> j)jB q 4o J:0 c:q| .B>.(0>.( pI> JqB0 (j|+`hhc6J "]. tr (" a -z" ,Z+" #'()+,-./ =@ MTV_" <<92);P=- >s{[q="+ ---+"+ Z *(6 + s.size)," |:#{s }:SPONS OR S",q]} ;f=40;c= E+R=D["4 =8]?:B . B@C / C<<7_? <5<8]?66 _9A8;;==BC]_ _:_C??B`> >]A @@ AAB B CC__``]]" ,"$AC-8 <:4@. -1`$]8-1C_` 4)5-7C 74C? 5A5 , 574C9B=C] 99`=<5219?(C(2<9C2 19?B86/)'1&_06/)'1&_006(2<9.,:>A_<_<_@<'3333;7CA7@6@3 >:CA,`*C%;>7+2%>A:+2 %:A7<,`*C8++@6&*_"];S=[[["EXECUTIVE:ADMINISTRATOR","Abb y:Phoenix"],["EVENT: PRODUCE R ","Hea ther :Johnson" ],["S PONSORSHIP:CONSULTAN T","Shirley:B ai les "] ,],[[(t= "PR OGR AM:")+"CHAIR","Sarah :Mei"],[t+="DIRECTOR" ,"E va n:Phoe n ix"],[t, "Ma rty :Haught"],],[[t="TRA CKDIRECTOR","Akira:Matsuda"] ,[t ," Corali n e:Ada:Eh mke "],[t,"Courteney:Ervin"],],[[t,"Derek:Prior"],[t,"N adi a:O du nayo"],[ t," Nic kolas:Means"],]].map{|a|a.flat_map{|x,y|[E]*5+[x+Z* x.s ize,Z *y.s i ze+ y]} [5..-1]};S[1,0]=[p,"[[:Program:Committee:]]"];[p,C.gsub(/./){Z==$&?c.slice!(0,1).tr("]_`","##;"):Z} .lines[11,24],p,'<<-"RubyConf:2017":--:@New_Orleans.->>',p,"[[:Planning:Team:]]",*S,p,P["DIAMOND"], p,L.scan(/.{92}/)[0,7],p,P["PLATINUM"],p,L[7*92..-1].scan(/.{47}/),p,P["GOLD"],*[["STITCH:FIX","sqr een"],["Braintree","HEROKU"],["entelo","SENTRY"],["DATADOG","ROOSTIFY"]].map{|a|f=40-f;a.flat_map{| s|l=Z*f;r=Z*f=40-f;[E,E,l+s+r,l+?=*s.size+r,E,E]}},p,P["BRONZE"]+[E,"BRAKEMANPRO"]+[E]*4+P["OTHER"] +[E,"covermymeds",E,"Google:Cloud:Platform"],p,"Brought:to:you:by:the:folks:at:Ruby:Central",p,"Rub yConf:2017",p,[?%*39,u="%%"+Z*35+"%%","%%::::Remember!::This:is:a:Quine!::::%%",u,"%%:This:banner:i s:a:valid:Ruby:code.:%%",u,?%*39,],p,["The:original:source:code:follows...",E,E,"---8<---"*8],p,C.g sub(/./){Z==$&?(c=R.slice!(0,1).ord;27.chr+"[#{c-52}m#{Z}"+27.chr+"[0m"):$&}.lines].flat_map{|s|(s) ?(s=[*s];s.map{|l|l.center(99).rstrip}+[E]*[0,(24-s.size)/2].max+[p]):[E]*24}.map{|s|n=(s)?(puts(Z= =s[0]?s.tr(?:,Z):s);1):92;t=Time.new;o<