tag:blogger.com,1999:blog-63099467181758907352024-02-08T23:35:20.790+09:00mamememoRuby, Quine, esoteric languages, and what notYusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.comBlogger13125tag:blogger.com,1999:blog-6309946718175890735.post-136015124486069922020-05-23T13:02:00.000+09:002020-05-23T13:02:38.737+09:00CPU-intensive Ruby/Python code runs slower on default-configured Docker<h2>Summary</h2>
<p>Docker enables security mechanism for Spectre vulnerability by default. This degrades the performance of almost all CPU-intensive programs, especially, interpreters like Ruby and Python. The execution time becomes about twice at worst.</p>
<h2>Problem</h2>
<p>This is a simple benchmark program that runs an empty loop 100M times.</p>
<p><code><pre>
i=0
while i < 100_000_000
i+=1
end
</pre></code></p>
<p>It takes 1.3 sec. on the host, but it does 2.5 sec. on a Docker container.</p>
<p>On the host:</p>
<p><code><pre>
$ ruby -ve 't = Time.now; i=0;while i<100_000_000;i+=1;end; puts "#{ Time.now - t } sec"'
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
1.321703922 sec
</pre></code></p>
<p>On a Docker container:</p>
<p><code><pre>
$ docker run -it --rm ruby:2.7 ruby -ve 't = Time.now; i=0;while i<100_000_000;i+=1;end; puts "#{ Time.now - t } sec"'
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
2.452876383 sec
</pre></code></p>
<p>If you specify an option "<code>--security-opt seccomp=unconfined</code>" for <code>docker run</code> command, it runs as fast as the host.</p>
<p><code><pre>
$ docker run --security-opt seccomp=unconfined -it --rm ruby:2.7 ruby -ve 't = Time.now; i=0;while i<100_000_000;i+=1;end; puts "#{ Time.now - t } sec"'
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
1.333669449 sec
</pre></code></p>
<p>The above example uses Ruby, but I confirmed the problem with Python too. (Two-line code "<code>i=0</code> / <code>while i<100000000; i+=1</code>" took 7.0 sec. on the host and 11 sec. on Docker.)</p>
<p>Note that this code does not access file system nor network. In fact, it issues no syscall at all in the main loop. Thus, in this case, there is no virtualization overhead of Docker.</p>
<p>You may not reproduce this issue depending upon the kernel configuration as described later.</p>
<h2>Why</h2>
<p>The recent Linux kernel implements some mitigation options against <a href="https://en.wikipedia.org/wiki/Spectre_(security_vulnerability">Spectre vulnerability</a>).</p>
<p>One of them suppresses indirect branch prediction (called STIBP). This makes CPU-intensive code 2x slower, so it is <a href="https://www.zdnet.com/article/linus-torvalds-after-big-linux-performance-hit-spectre-v2-patch-needs-curbs/">disabled by default</a>.
Docker, however, runs a container with the option enabled.</p>
<p>(Koichi Sasada says it may depend the kernel configuration of each distribution. See <a href="https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/spectre.html#turning-on-mitigation-for-spectre-variant-1-and-spectre-variant-2">Spectre Side Channels — The Linux Kernel documentation</a>.)</p>
<p>This option makes almost all programs slower. According to <a href="https://www.phoronix.com/scan.php?page=article&item=linux-420-stibp&num=2">this article</a>, it reduced the performance of Java, Node.js, memcached, PHP, and so on. Interpreters like Ruby and Python are especially affected because they heavily depends upon indirect branches, e.g., switch/case, <a href="https://en.wikipedia.org/wiki/Threaded_code#Direct_threading">direct threading</a>, and so on. They run faster on the host because the option is off, and slower on Docker because the option is on.</p>
<p>Using "<code>perf stat</code>", I measured branch miss count: 522,663 on the host, and 199,260,442 on Docker.</p>
<p>With <code>--security-opt seccomp=unconfined</code> (vulnerable against Spectre):</p>
<code><pre>
Performance counter stats for process id '153095':
1,235.67 msec task-clock # 0.618 CPUs utilized
8 context-switches # 0.006 K/sec
0 cpu-migrations # 0.000 K/sec
2 page-faults # 0.002 K/sec
4,284,307,990 cycles # 3.467 GHz
13,903,977,890 instructions # 3.25 insn per cycle
1,700,742,230 branches # 1376.378 M/sec
522,663 branch-misses # 0.03% of all branches
2.000223507 seconds time elapsed
</pre></code>
<p>Without <code>--security-opt seccomp=unconfined</code> (not vulnerable against Spectre):</p>
<code><pre>
Performance counter stats for process id '152556':
3,300.42 msec task-clock # 0.550 CPUs utilized
16 context-switches # 0.005 K/sec
2 cpu-migrations # 0.001 K/sec
2 page-faults # 0.001 K/sec
11,912,594,779 cycles # 3.609 GHz
13,906,818,105 instructions # 1.17 insn per cycle
1,701,237,677 branches # 515.460 M/sec
199,260,442 branch-misses # 11.71% of all branches
6.000985834 seconds time elapsed
</pre></code>
<p>This issue is reproduced only when STIBP is "conditional", which means off by default but it can be enabled by <a href="https://en.wikipedia.org/wiki/Seccomp">seccomp</a>. If STIBP is "disabled", the issue does not occur; both the host and Docker run faster (but vulnerable). If STIBP is "forced", the issue does not occur; both the host and Docker run slower. You can see the configuration of your system in <code>/sys/devices/system/cpu/vulnerabilities/spectre_v2</code>.</p>
<p>In addition to STIBP, the security mitigation "<code>spec_store_bypass_disable</code>", which is against side-channel attacks of <a href="https://en.wikipedia.org/wiki/Speculative_Store_Bypass">speculative store bypass</a>, also degrades the performance. The option <code>--security-opt seccomp=unconfined</code> seems to suppress the measure too. According to Koichi Sasada's investigation, the slowdown was removed by kernel options <code>spectre_v2_user=off spec_store_bypass_disable=off</code>.</p>
<h2>Solution</h2>
<p>Unfortunately, there is no recommended solution for this issue. The option <code>--security-opt seccomp=unconfined</code> (or <code>--privileged</code>) solves the issue, but in general, I cannot recommend the usage because it is vulnerable against Spectre attacks.</p>
<p>Fortunately, this problem is only for CPU-intensive programs. Since almost all (Ruby on Rails) Web applications are IO-intensive or memory-intensive, you will see no significant performance improvement even if you specify the options, perhaps. Thus, I recommend you don't care the problem for a while.</p>
<p>In a long term: if CPUs adderss the Spectre attacks, this issue will be fundamentally solved. (But you must wait for a decade.) Or, <a href="https://rubykaigi.org/2019/presentations/ko1.html">a new VM approach based on contest threading</a> proposed by Koichi Sasada, does not depend on indirect branches, so it may solve this issue. (But you must wait for a few years at least.)</p>
<h2>Acknowledgment</h2>
<ul>
<li>Those who replied to <a href="https://twitter.com/mametter/status/1263399275368599552">my tweet</a> (Especially, <a href="https://twitter.com/ryot_a_rai/status/1263425271232753666">@ryotarai</a> found <code>--security-opt seccomp=unconfined</code>.)</li>
<li>Those who joined the discussion on #container channel in <a href="https://ruby-jp.github.io/">ruby-jp Slack</a> (Mainly, Koichi Sasada investigated how the option works.)</li>
<li>Ruby committers</li>
</ul>
<h2>Postscript</h2>
<p>My benchmark program called <a href="https://github.com/mame/optcarrot">optcarrot</a>, which is one of the targets for Ruby 3x3 project, is heavily affected by this issue: it runs 33 fps on the host, 14 fps on Docker.</p>
Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com2tag:blogger.com,1999:blog-6309946718175890735.post-36850568981256924722019-06-16T09:10:00.000+09:002020-05-23T13:03:06.309+09:00A Brief History of Pipeline Operator<p>Pipeline operator is experimentally introduced to the bleeding edge of Ruby. For some reason, this seems to lead a lot of people to leave their comments on <a href="https://bugs.ruby-lang.org/issues/15799">the ticket of the bug tracker</a>.</p>
<p>I investigated the history of the pipeline operator. I’m not an expert on the operator, so let me know if this article contains any wrong description.</p>
<h2>What is pipeline operator?</h2>
<p>This is what pipeline operator is from users’ perspective:</p>
<pre><code>x |> f |> g |> h # identical to h(g(f(x)))
</code></pre>
<p>In the function-application expression <code>h(g(f(x)))</code>, the order of the function call (<code>f</code>→<code>g</code>→<code>h</code>) is different from the literal order in the program (<code>h</code>→<code>g</code>→<code>f</code>). This problem becomes more serious when the function names are longer:</p>
<pre><code>wonderful_process_h(
marvelous_process_g(
fantastic_process_f(
astonishing_argument_x
)
)
)
</code></pre>
<p>It also suffers from indentation hell.</p>
<p>The pipeline operator <code>|></code> solves both problems:</p>
<pre><code>astonishing_argument_x
|> fantastic_process_f
|> marvelous_process_g
|> wonderful_process_h
</code></pre>
<p>There are neither “order” problem nor indent problem.</p>
<h2>Isabelle/ML</h2>
<p>According to <a href="https://fsharp.org/history/hopl-draft-1.pdf">The Early History of F#</a>, the first language that introduced pipeline operator is Isabelle/ML. We can read <a href="https://blogs.msdn.microsoft.com/dsyme/2011/05/17/archeological-semiotics-the-birth-of-the-pipeline-symbol-1994/">the discussion at 1994</a>.</p>
<p>According to the discussion, its purpose was to avoid the above two problems: programmers want to write function names as their execution order. For example, we write the following code in ML to make AAA, add BBB to it, add CCC to it, and then add DDD to it:</p>
<pre><code>add DDD (add CCC (add BBB (make AAA ())))
</code></pre>
<p>By using <code>|></code>, we can write the same program as follows:</p>
<pre><code>make AAA
|> add BBB
|> add CCC
|> add DDD
</code></pre>
<p>The operator was called “also” in the original proposal. In fact, MLs let programmers define infix operators using even alphabets, and can write <code>make AAA add BBB add CCC add DDD</code> by defining <code>add</code> infix operator based on <code>add</code> function. So, you actually don’t need another feature like “<code>also</code>”, but it would avoid messing the program with a bunch of <code>add_XXX</code> infix declarations.</p>
<p>Here are some commits involving <code>also</code> and <code>|></code> from Isabelle/ML repository.</p>
<ul>
<li><a href="http://isabelle.in.tum.de/repos/isabelle/rev/daca5b594fb3#l1.8"><code>also</code> operator</a></li>
<li><a href="http://isabelle.in.tum.de/repos/isabelle/rev/e9ba9f7e2542#l1.518">An example usage of <code>also</code></a></li>
<li><a href="http://isabelle.in.tum.de/repos/isabelle/rev/c8171ee32744#l1.9"><code>also</code> was changed to <code>|></code></a></li>
</ul>
<h2>F</h2>
<p>F# is a language for .NET Framework. It is based on OCaml.</p>
<p>Pipeline operator has been popular because it was introduced by F#. “Expert F#”, a book written by Don Syme who is the designer of F#, says “The |> forward pipe operator is perhaps the most important operator in F# programming.”</p>
<p>According to <a href="https://fsharp.org/history/hopl-draft-1.pdf">The Early History of F#</a>, pipeline operator was added to the F# standard library in 2003. The reason why <code>|></code> is particularly important is not only because the function order is good, but also because it is easy for type inference. The type-inference algorithm of F# is left-to-right, based on information available earlier in the program. Consider the following program:</p>
<pre><code>let data = ["one"; "three"]
data |> List.map (fun s -> s.Length)
</code></pre>
<p>In the above case, the type inference knows that <code>data</code> is <code>string list</code>, so no type annotation is required. However, if we write it in a traditional style without <code>|></code>,</p>
<pre><code>List.map (fun (s: string) -> s.Length) data
</code></pre>
<p>An annotation <code>s: string</code> is required because <code>data</code> follows the anonymous function. (This example is attributed to “The Early History of F#”.)</p>
<p>Pipeline operator in F# was introduced back to OCaml in 2013. F# is based on OCaml, but with regards to pipeline operator, F# was prior to OCaml.</p>
<h2>Three “facts” about pipeline operator in ML</h2>
<p>I digress from history. I’d like to summarize some facts of pipeline operator in ML family.</p>
<p>In ML, <code>|></code> is not special. It is not a built-in operator but is merely a normal function. This is a cool hack that functional programming lovers like. There are three facts to make the hack possible.</p>
<ol>
<li>Users can define their own infix operator.</li>
<li>Currying is built-in by default.</li>
<li>Most functions accept a “primary” argument as the final argument.</li>
</ol>
<p>1 is cool, but 2 and 3 look particularly important.</p>
<p>By “primary”, I mean the subjective argument of a function; for example, a list for list manipulation function, an array for array manipulation function, etc. In F#, most functions are carefully designed to accept their “primary” argument at the last. For example, <code>List.map</code> accepts a closure as a first argument, a list as a second argument, and then returns a new list.</p>
<pre><code>List.map : ('a -> 'b) -> 'a list -> 'b list
Array.map : ('a -> 'b) -> 'a[] -> 'b[]
Option.map : ('a -> 'b) -> 'a option -> 'b option
Seq.map : ('a -> 'b) -> #seq<'a> -> seq<'b>
</code></pre>
<p>Thanks to these facts, we can define <code>|></code> just as follow. Great!</p>
<pre><code>let (|>) x f = f x
</code></pre>
<h2>Pipeline operator and method chain</h2>
<p>As I said, <code>|></code> in F# is used for chaining functions in the execution order: <code>x |> f |> g |> h</code>.</p>
<p>By the way, a method chain in object-oriented programs is also used for chaining methods in the execution order: <code>x.f().g().h()</code>.</p>
<p>I’m not sure whether F# intentionally introduced <code>|></code> being on aware of the above fact, or it was just a coincidence. Anyway, some people think that the two things are related.</p>
<ul>
<li><a href="https://stackoverflow.com/questions/7698133/method-chaining-vs-pipe-operator">map - Method Chaining vs |> Pipe Operator - Stack Overflow
</a></li>
<li><a href="http://byatool.com/uncategorized/fsharp-using-the-pipe-operartor-to-chain-methods/">FSharp: Using the Pipe Operartor to Chain Methods - ByATool</a></li>
<li><a href="https://github.com/facebook/reason/issues/1638">Feature: Using dot operator instead of pipe operator · Issue #1638 · facebook/reason</a></li>
<li><a href="https://www.slideshare.net/igeta/fluent-featureinfsharpom2010">Fluent Feature in F# (slideshare, in Japanese)</a></li>
</ul>
<h2>Elixir</h2>
<p>Returning to history.</p>
<p>Elixir introduced pipeline operator. According to José Valim, the author of Elixir, <a href="https://elixirforum.com/t/which-language-first-introduced-the-pipe-operator/16791/6">it came from F#</a>. Its appearance is really similar to F#.</p>
<pre><code>x |> f |> g |> h
</code></pre>
<p>However, it is quite different in terms of the language specifications. In Elixir, <code>|></code> is not a normal operator, but a built-in language construction.</p>
<pre><code>x |> f(args..) # identical to f(x, args...)
</code></pre>
<p>It first evaluates the left side (<code>x</code>), and passes it to the right call as the first (not last) argument.</p>
<p>If <code>|></code> is a normal operator, the left and right expression are independent. Consider an addition expression <code>expr1 + expr2</code>. The two <code>expr</code>s are both self-contained expressions. In <code>expr1 |> expr2</code> of F#, <code>expr2</code> is independent. If <code>expr2</code> is a function that accepts two or more arguments, we can exploit currying and partial application. The “primary” argument that is typically passed in a pipeline is final, so the hack shines!</p>
<p>The right side of <code>|></code> in Elixir is not an independent expression. It is an incomplete function call that lacks the first argument. So, Elixir’s <code>|></code> is not a normal operator; rather it is considered a language construction.</p>
<p>The rationale of the Elixir’s design is, that the three facts are all unsatisfied in Elixir. It cannot define infix operator freely; there is no currying by default; most functions accept its “primary” argument at the first. Therefore, in my opinion, Elixir’s <code>|></code> is completely different from F#’s, though it looks similar.</p>
<p>When considering a new feature on a “practical” programming language, I think we have to care much about what users see on its appearance, rather than what some language maniacs say. That is, if a new operator in a language A has the same syntax as an operator in some other language B, and they work differently, it might not so important from the user of the language A.</p>
<h2>Ruby</h2>
<p>Finally, the development version of Ruby introduced pipeline operator only a few days ago.</p>
<pre><code>x |> f |> g |> h # identical to x.f().g().h()
</code></pre>
<pre><code>x |> f(args...) # identical to x.f(args...)
</code></pre>
<p>It first evaluates the left side. And then, it calls a method on that result. The method name and arguments are written on the right side.</p>
<p>Like Elixir, Ruby does not satisfy the three facts. So, Ruby introduced <code>|></code> as a new language construction, not as a simple operator.</p>
<p><code>|></code> in Elixir passes the left expression as the first argument of the right function call. On the other hand, <code>|></code> in Ruby passes it as a receiver of the right method call. In Ruby, the “primary” argument is typically a receiver. So this is a natural choice, in a sense.</p>
<p>What is this feature practically good for? It is arguable. But I’d say that it is useful to explicitly write a multi-line method chain. And we can omit parentheses.</p>
<pre><code>(1..)
.take(10)
.each {|x| p x }
1..
|> take 10
|> each {|x| p x }
</code></pre>
<p>You might feel more comfortable with the later style. Mind you, either is fine for me.</p>
<p>Anyway, the feature has some problems.</p>
<ul>
<li>It is different from Elixir’s.</li>
<li>It is almost the same to the existing method call syntax (<code>.</code>).</li>
</ul>
<p>My opinion for the first point: As far as I know, this is the first case to add pipeline operator to object-oriented language. Just saying “it is different from Elixir!” is not helpful at all because Ruby is not Elixir and Elixir is not object-oriented. We need to find a good design suitable for Ruby. Besides, most of the normal methods in Ruby accept the “primary” argument as a receiver. Function-style methods that accept the “primary” one in the first argument are relatively few. (Of course, there are some exceptions like <code>File.join</code>, <code>Math.log</code>, etc.) So, Elixir-style pipeline operator might not be very useful in Ruby.</p>
<p>My opinion for the second point: we don’t have to hurry. If matz admits that there is no use case, he will remove the feature before it is released. The next release is planned in December.</p>
<p>Good news is that Matz also realizes those problems and is now considering another candidate of its name and symbol. Then, Ruby’s new “pipeline” still has a chance to be a vaporware soon? I’m not sure. Keep your eyes on the development of Ruby.</p>
<h2>Conclusion</h2>
<p>I briefly explained the history of pipeline operator. I just investigated all on one night, so let me know if I was wrong. (I’m a non-native speaker, so don’t get me wrong if the expression is not appropriate.)</p>
<h2>Acknowledgment</h2>
<p>Keiichiro Shikano kindly reviewed the draft of this article.</p>
<!--
# A Brief History of Pipeline Operator
Pipeline operator is experimentally introduced to the bleeding edge of Ruby. For some reason, this seems to lead a lot of people to leave their comments on [the ticket of the bug tracker](https://bugs.ruby-lang.org/issues/15799).
I investigated the history of the pipeline operator. I'm not an expert on the operator, so let me know if this article contains any wrong description.
## What is pipeline operator?
This is what pipeline operator is from users’ perspective:
```
x |> f |> g |> h # identical to h(g(f(x)))
```
In the function-application expression `h(g(f(x)))`, the order of the function call (`f`→`g`→`h`) is different from the literal order in the program (`h`→`g`→`f`). This problem becomes more serious when the function names are longer:
```
wonderful_process_h(
marvelous_process_g(
fantastic_process_f(
astonishing_argument_x
)
)
)
```
It also suffers from indentation hell.
The pipeline operator `|>` solves both problems:
```
astonishing_argument_x
|> fantastic_process_f
|> marvelous_process_g
|> wonderful_process_h
```
There are neither "order" problem nor indent problem.
## Isabelle/ML
According to [The Early History of F#](https://fsharp.org/history/hopl-draft-1.pdf), the first language that introduced pipeline operator is Isabelle/ML. We can read [the discussion at 1994](https://blogs.msdn.microsoft.com/dsyme/2011/05/17/archeological-semiotics-the-birth-of-the-pipeline-symbol-1994/).
According to the discussion, its purpose was to avoid the above two problems: programmers want to write function names as their execution order. For example, we write the following code in ML to make AAA, add BBB to it, add CCC to it, and then add DDD to it:
```
add DDD (add CCC (add BBB (make AAA ())))
```
By using `|>`, we can write the same program as follows:
```
make AAA
|> add BBB
|> add CCC
|> add DDD
```
The operator was called "also" in the original proposal. In fact, MLs let programmers define infix operators using even alphabets, and can write `make AAA add BBB add CCC add DDD` by defining `add` infix operator based on `add` function. So, you actually don't need another feature like "`also`", but it would avoid messing the program with a bunch of `add_XXX` infix declarations.
Here are some commits involving `also` and `|>` from Isabelle/ML repository.
* [`also` operator](http://isabelle.in.tum.de/repos/isabelle/rev/daca5b594fb3#l1.8)
* [An example usage of `also`](http://isabelle.in.tum.de/repos/isabelle/rev/e9ba9f7e2542#l1.518)
* [`also` was changed to `|>`](http://isabelle.in.tum.de/repos/isabelle/rev/c8171ee32744#l1.9)
## F#
F# is a language for .NET Framework. It is based on OCaml.
Pipeline operator has been popular because it was introduced by F#. "Expert F#", a book written by Don Syme who is the designer of F#, says "The |> forward pipe operator is perhaps the most important operator in F# programming."
According to [The Early History of F#](https://fsharp.org/history/hopl-draft-1.pdf), pipeline operator was added to the F# standard library in 2003. The reason why `|>` is particularly important is not only because the function order is good, but also because it is easy for type inference. The type-inference algorithm of F# is left-to-right, based on information available earlier in the program. Consider the following program:
```
let data = ["one"; "three"]
data |> List.map (fun s -> s.Length)
```
In the above case, the type inference knows that `data` is `string list`, so no type annotation is required. However, if we write it in a traditional style without `|>`,
```
List.map (fun (s: string) -> s.Length) data
```
An annotation `s: string` is required because `data` follows the anonymous function. (This example is attributed to "The Early History of F#".)
Pipeline operator in F# was introduced back to OCaml in 2013. F# is based on OCaml, but with regards to pipeline operator, F# was prior to OCaml.
## Three "facts" about pipeline operator in ML
I digress from history. I'd like to summarize some facts of pipeline operator in ML family.
In ML, `|>` is not special. It is not a built-in operator but is merely a normal function. This is a cool hack that functional programming lovers like. There are three facts to make the hack possible.
1. Users can define their own infix operator.
2. Currying is built-in by default.
3. Most functions accept a "primary" argument as the final argument.
1 is cool, but 2 and 3 look particularly important.
By "primary", I mean the subjective argument of a function; for example, a list for list manipulation function, an array for array manipulation function, etc. In F#, most functions are carefully designed to accept their "primary" argument at the last. For example, `List.map` accepts a closure as a first argument, a list as a second argument, and then returns a new list.
```
List.map : ('a -> 'b) -> 'a list -> 'b list
Array.map : ('a -> 'b) -> 'a[] -> 'b[]
Option.map : ('a -> 'b) -> 'a option -> 'b option
Seq.map : ('a -> 'b) -> #seq<'a> -> seq<'b>
```
Thanks to these facts, we can define `|>` just as follow. Great!
```
let (|>) x f = f x
```
## Pipeline operator and method chain
As I said, `|>` in F# is used for chaining functions in the execution order: `x |> f |> g |> h`.
By the way, a method chain in object-oriented programs is also used for chaining methods in the execution order: `x.f().g().h()`.
I'm not sure whether F# intentionally introduced `|>` being on aware of the above fact, or it was just a coincidence. Anyway, some people think that the two things are related.
* [map - Method Chaining vs |> Pipe Operator - Stack Overflow
](https://stackoverflow.com/questions/7698133/method-chaining-vs-pipe-operator)
* [FSharp: Using the Pipe Operartor to Chain Methods - ByATool](http://byatool.com/uncategorized/fsharp-using-the-pipe-operartor-to-chain-methods/)
* [Feature: Using dot operator instead of pipe operator · Issue #1638 · facebook/reason](https://github.com/facebook/reason/issues/1638)
* [Fluent Feature in F# (slideshare, in Japanese)](https://www.slideshare.net/igeta/fluent-featureinfsharpom2010)
## Elixir
Returning to history.
Elixir introduced pipeline operator. According to José Valim, the author of Elixir, [it came from F#](https://elixirforum.com/t/which-language-first-introduced-the-pipe-operator/16791/6). Its appearance is really similar to F#.
```
x |> f |> g |> h
```
However, it is quite different in terms of the language specifications. In Elixir, `|>` is not a normal operator, but a built-in language construction.
```
x |> f(args..) # identical to f(x, args...)
```
It first evaluates the left side (`x`), and passes it to the right call as the first (not last) argument.
If `|>` is a normal operator, the left and right expression are independent. Consider an addition expression `expr1 + expr2`. The two `expr`s are both self-contained expressions. In `expr1 |> expr2` of F#, `expr2` is independent. If `expr2` is a function that accepts two or more arguments, we can exploit currying and partial application. The "primary" argument that is typically passed in a pipeline is final, so the hack shines!
The right side of `|>` in Elixir is not an independent expression. It is an incomplete function call that lacks the first argument. So, Elixir's `|>` is not a normal operator; rather it is considered a language construction.
The rationale of the Elixir's design is, that the three facts are all unsatisfied in Elixir. It cannot define infix operator freely; there is no currying by default; most functions accept its "primary" argument at the first. Therefore, in my opinion, Elixir's `|>` is completely different from F#'s, though it looks similar.
When considering a new feature on a "practical" programming language, I think we have to care much about what users see on its appearance, rather than what some language maniacs say. That is, if a new operator in a language A has the same syntax as an operator in some other language B, and they work differently, it might not so important from the user of the language A.
## Ruby
Finally, the development version of Ruby introduced pipeline operator only a few days ago.
```
x |> f |> g |> h # identical to x.f().g().h()
```
```
x |> f(args...) # identical to x.f(args...)
```
It first evaluates the left side. And then, it calls a method on that result. The method name and arguments are written on the right side.
Like Elixir, Ruby does not satisfy the three facts. So, Ruby introduced `|>` as a new language construction, not as a simple operator.
`|>` in Elixir passes the left expression as the first argument of the right function call. On the other hand, `|>` in Ruby passes it as a receiver of the right method call. In Ruby, the "primary" argument is typically a receiver. So this is a natural choice, in a sense.
What is this feature practically good for? It is arguable. But I'd say that it is useful to explicitly write a multi-line method chain. And we can omit parentheses.
```
(1..)
.take(10)
.each {|x| p x }
1..
|> take 10
|> each {|x| p x }
```
You might feel more comfortable with the later style. Mind you, either is fine for me.
Anyway, the feature has some problems.
* It is different from Elixir's.
* It is almost the same to the existing method call syntax (`.`).
My opinion for the first point: As far as I know, this is the first case to add pipeline operator to object-oriented language. Just saying "it is different from Elixir!" is not helpful at all because Ruby is not Elixir and Elixir is not object-oriented. We need to find a good design suitable for Ruby. Besides, most of the normal methods in Ruby accept the "primary" argument as a receiver. Function-style methods that accept the "primary" one in the first argument are relatively few. (Of course, there are some exceptions like `File.join`, `Math.log`, etc.) So, Elixir-style pipeline operator might not be very useful in Ruby.
My opinion for the second point: we don't have to hurry. If matz admits that there is no use case, he will remove the feature before it is released. The next release is planned in December.
Good news is that Matz also realizes those problems and is now considering another candidate of its name and symbol. Then, Ruby's new "pipeline" still has a chance to be a vaporware soon? I'm not sure. Keep your eyes on the development of Ruby.
## Conclusion
I briefly explained the history of pipeline operator. I just investigated all on one night, so let me know if I was wrong. (I'm a non-native speaker, so don't get me wrong if the expression is not appropriate.)
## Acknowledgment
Keiichiro Shikano kindly reviewed the draft of this article.
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com5tag:blogger.com,1999:blog-6309946718175890735.post-24615729306525529572010-12-23T19:04:00.005+09:002010-12-24T23:42:45.139+09:00Merry Quine-mas 2010<p>Tonight is the eve of the anniversary of <a href="http://en.wikipedia.org/wiki/W._V._Quine">W. V. Quine</a>'s death. (in Japanese time zone :-)</p>
<pre><code> %;';;X= %q(x=1; z="%c"%
32;eval %w(w=N= Merry =128;r=
z*79+$/; ;p=open" / dev/dsp
","w"rescue$_;/ / ;eval"s
rand(%s)"%$*[ d=0];a=[];s=(r+z+% (%;';;X=#{z* 3}%q(#{X});e val(X))
+r*=23).l ines.map{|l|l.chop+ r};t=proc{|y|s [y][x-1,w].sca n(/\S
/){s[y+1][m=x -1+$` .size ,1]== z&&a< <[$&,m, y,s[y
][m]=$/]};y};t[ 23];f =(0.. 1071) .map{|i|c,x,y =a.shuffle!. pop;s
[y][x]=z ;[794-46 .03*i **0.4 +y/k= (3+ra nd*w= 3)/9,[t
[t[y]-1 ],x,c], (0..y /k).m ap{[y -=k,0.5+x+=k*r and*2-k,?*]}]} ;"|ii
xCG40_| CK8&d9B ix0,B J?B?G ^K9CG CJ|ii>Ci?9CV; =*-*.sEA.2gA w>dc=
: `:z:J> s 9QvA:> J taaA>` : @AP;Fa c
y =Anm|?Bdqr h ?<CDJCD<IU < DuCJ>:d_C? h ?<CWC:'.'+ r
9 A.*. '>| =*- * .:9i 9A> :JC s :Q> :>9 CJA= g `;C i9A >M". b
yt es{|c|a+=([% [+. 5$2-'30&)"/: (7% !*][c%19].or d]* [47,23,11][4 -c
/1 9]< <3 3). *c/ 95 +1} ;$ ><< (T= "% q\x 7e
' #{e="\x1 b [ "}H#{e}J # { e}?25")+ " l ";863.do w
n to(0){|i|b=r + [ "'"*25]*2*"_ ( c )_2010_@mame t t er,@hirekoke "
;f.map{ |j,x,v |i<j&&( y,x,c= v.pop| |x;x<0| |x>78| |b[x+y.
to_i*80]=0<i&&i< 40??#:c)};($><<( i>0?e+"H":T+"h") +b).flush;(p)?4.
times{N. times{v =8;4.tim es{|l|t =a[l*N* 9+d/N%11 52];t>3 3&&v+=(d
*0.11*4**(t/24 .0-l%3))%8<=>4 };d+=1;p<<[16* v].pack("C*")}
;p.flush}: sleep(0.1) };puts)*"" ;);eval(X)
'''''''''''''''''''''''''_(c)_2010_@mametter,@hirekoke'''''''''''''''''''''''''
</code></pre>
<p>Save the code as "quinemas2010.rb" and run it under an terminal bigger than 80 x 24. You can use cygwin if you're a windows user. You may need to use "aoss" or "padsp" if you're using Un*x. I tested it with ruby 1.8.7p299 and 1.9.2p0.</p>
<p>A screencast for you guys who are lazy:</p>
<p><object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/r0eaf9iLKxg?fs=1&hl=ja_JP"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/r0eaf9iLKxg?fs=1&hl=ja_JP" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object></p>
<h2>FAQ</h2>
<ul>
<li>Q. Is this a <em>pseudo</em>-Quine because its output is not strictly equal to the code?
<ul><li>A. Yes. This is a Quine generator. Run it as follows. You'll find tmp1.rb is certainly a Quine.</li></ul></li>
</ul>
<pre>$ ruby quinemas2010.rb 0 > tmp1.rb
$ ruby tmp1.rb 0 > tmp2.rb
$ diff tmp1.rb tmp2.rb</pre>
<ul>
<li><p>Q. What does the command line argument mean?</p>
<ul><li>A. A random seed which affects how to snow.</li></ul></li>
<li><p>Q. How does it animate?</p>
<ul><li>A. It just prints each frame with the aid of escape sequence. Because it uses only <a href="http://en.wikipedia.org/wiki/ANSI_escape_code">ANSI escape code</a>, it works on almost all terminal emulator (but not cmd.exe).</li></ul></li>
<li><p>Q. How does it play a sound?</p>
<ul><li>A. It writes a sound wave directly to /dev/dsp (see <a href="http://en.wikipedia.org/wiki/Open_Sound_System">Open Sound System</a>).</li></ul></li>
</ul>
<p>translated from <a href="http://d.hatena.ne.jp/ku-ma-me/20101224/p1">mamememo in Japanese (2010-12-24)</a>.</p>
<!--[markdown]
Tonight is the eve of the anniversary of [W. V. Quine](http://en.wikipedia.org/wiki/W._V._Quine)'s death. (in Japanese time zone :-)
%;';;X= %q(x=1; z="%c"%
32;eval %w(w=N= Merry =128;r=
z*79+$/; ;p=open" / dev/dsp
","w"rescue$_;/ / ;eval"s
rand(%s)"%$*[ d=0];a=[];s=(r+z+% (%;';;X=#{z* 3}%q(#{X});e val(X))
+r*=23).l ines.map{|l|l.chop+ r};t=proc{|y|s [y][x-1,w].sca n(/\S
/){s[y+1][m=x -1+$` .size ,1]== z&&a< <[$&,m, y,s[y
][m]=$/]};y};t[ 23];f =(0.. 1071) .map{|i|c,x,y =a.shuffle!. pop;s
[y][x]=z ;[794-46 .03*i **0.4 +y/k= (3+ra nd*w= 3)/9,[t
[t[y]-1 ],x,c], (0..y /k).m ap{[y -=k,0.5+x+=k*r and*2-k,?*]}]} ;"|ii
xCG40_| CK8&d9B ix0,B J?B?G ^K9CG CJ|ii>Ci?9CV; =*-*.sEA.2gA w>dc=
: `:z:J> s 9QvA:> J taaA>` : @AP;Fa c
y =Anm|?Bdqr h ?<CDJCD<IU < DuCJ>:d_C? h ?<CWC:'.'+ r
9 A.*. '>| =*- * .:9i 9A> :JC s :Q> :>9 CJA= g `;C i9A >M". b
yt es{|c|a+=([% [+. 5$2-'30&)"/: (7% !*][c%19].or d]* [47,23,11][4 -c
/1 9]< <3 3). *c/ 95 +1} ;$ ><< (T= "% q\x 7e
' #{e="\x1 b [ "}H#{e}J # { e}?25")+ " l ";863.do w
n to(0){|i|b=r + [ "'"*25]*2*"_ ( c )_2010_@mame t t er,@hirekoke "
;f.map{ |j,x,v |i<j&&( y,x,c= v.pop| |x;x<0| |x>78| |b[x+y.
to_i*80]=0<i&&i< 40??#:c)};($><<( i>0?e+"H":T+"h") +b).flush;(p)?4.
times{N. times{v =8;4.tim es{|l|t =a[l*N* 9+d/N%11 52];t>3 3&&v+=(d
*0.11*4**(t/24 .0-l%3))%8<=>4 };d+=1;p<<[16* v].pack("C*")}
;p.flush}: sleep(0.1) };puts)*"" ;);eval(X)
'''''''''''''''''''''''''_(c)_2010_@mametter,@hirekoke'''''''''''''''''''''''''
Save the code as "quinemas2010.rb" and run it under an terminal bigger than 80 x 24. You can use cygwin if you're a windows user. You may need to use "aoss" or "padsp" if you're using Un*x. I tested it with ruby 1.8.7p299 and 1.9.2p0.
A screencast for you guys who are lazy:
<object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/r0eaf9iLKxg?fs=1&hl=ja_JP"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/r0eaf9iLKxg?fs=1&hl=ja_JP" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object>
## FAQ
- Q. Is this a *pseudo*-Quine because its output is not strictly equal to the code?
- A. Yes. This is a Quine generator. Run it as follows. You'll find tmp1.rb is certainly a Quine.
<pre>$ ruby quinemas2010.rb 0 > tmp1.rb
$ ruby tmp1.rb 0 > tmp2.rb
$ diff tmp1.rb tmp2.rb</pre>
- Q. What does the command line argument mean?
- A. A random seed which affects how to snow.
- Q. How does it animate?
- A. It just prints each frame with the aid of escape sequence. Because it uses only [ANSI escape code](http://en.wikipedia.org/wiki/ANSI_escape_code), it works on almost all terminal emulator (but not cmd.exe).
- Q. How does it play a sound?
- A. It writes a sound wave directly to /dev/dsp (see [Open Sound System](http://en.wikipedia.org/wiki/Open_Sound_System)).
translated from [mamememo in Japanese (2010-12-24)](http://d.hatena.ne.jp/ku-ma-me/20101224/p1).
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com7tag:blogger.com,1999:blog-6309946718175890735.post-28391014226351452432010-09-07T23:24:00.005+09:002010-09-07T23:37:05.987+09:00inline-ook: a library that allows you to embed Ook! program in Ruby script<p>In RubyKaigi 2010, Chad Fowler introduced <a href="http://www.dangermouse.net/esoteric/ook.html">Ook!</a> which is a programming language designed for orang-utans.</p>
<p>Ook! program is just like Ruby program, isn't it? <code>Ook. Ook! Ook. Ook?</code> can be interpreted as <code>Ook.Ook!(Ook.Ook?)</code> in Ruby. Thus I tried to embed Ook! program into Ruby program, and succeeded:</p>
<pre name="code" class="ruby">
require "inline-ook"
puts "Hello, Ruby!" #=> Hello, Ruby!
ook begin
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook. Ook? Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook.
Ook? Ook. Ook? Ook. Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook?
Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook! Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook.
Ook. Ook? Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook! Ook!
Ook! Ook! Ook! Ook. Ook? Ook. Ook? Ook. Ook! Ook. Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook. Ook.
Ook! Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook! Ook.
ook end #=> Hello, Ook!
puts "Hello, Ruby again!" #=> Hello, Ruby again!
</pre>
<p>You can write any Ook! program in Ruby program just by surrounding <code>ook begin</code> and <code>ook end</code>. You don't have to use here document. You don't have to apply any patch to ruby interpreter.</p>
<pre><code>$ ruby example/hello.ook.rb
Hello, Ruby!
Hello, Ook!
Hello, Ruby again!
</code></pre>
<p>You can install inline-ook as follows. I tested it with 1.8.7-p72 and 1.9.2-p0.</p>
<pre><code>$ gem install inline-ook
</code></pre>
<p>translated from <a href="http://d.hatena.ne.jp/ku-ma-me/20100907/p1">mamememo in Japanese (2010-09-07)</a>.</p>
<!--[markdown]
In RubyKaigi 2010, Chad Fowler introduced [Ook!](http://www.dangermouse.net/esoteric/ook.html) which is a programming language designed for orang-utans.
Ook! program is just like Ruby program, isn't it? <code>Ook. Ook! Ook. Ook?</code> can be interpreted as <code>Ook.Ook!(Ook.Ook?)</code> in Ruby. Thus I tried to embed Ook! program into Ruby program, and succeeded:
<pre name="code" class="ruby">
require "inline-ook"
puts "Hello, Ruby!" #=> Hello, Ruby!
ook begin
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook. Ook? Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook.
Ook? Ook. Ook? Ook. Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook?
Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook! Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook.
Ook. Ook? Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook! Ook!
Ook! Ook! Ook! Ook. Ook? Ook. Ook? Ook. Ook! Ook. Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook. Ook.
Ook! Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook! Ook.
ook end #=> Hello, Ook!
puts "Hello, Ruby again!" #=> Hello, Ruby again!
</pre>
You can write any Ook! program in Ruby program just by surrounding <code>ook begin</code> and <code>ook end</code>. You don't have to use here document. You don't have to apply any patch to ruby interpreter.
$ ruby example/hello.ook.rb
Hello, Ruby!
Hello, Ook!
Hello, Ruby again!
You can install inline-ook as follows. I tested it with 1.8.7-p72 and 1.9.2-p0.
$ gem install inline-ook
translated from [mamememo in Japanese (2010-09-07)](http://d.hatena.ne.jp/ku-ma-me/20100907/p1).
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com0tag:blogger.com,1999:blog-6309946718175890735.post-63145504340677465262010-09-05T17:21:00.003+09:002010-09-07T12:31:56.785+09:00The Qlobe<p>My Quines are sometimes specialized for Japanese. But to attend RubyConf, I should write "global" Quines.</p>
<pre><code>v=0000;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "##% ::##########" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "##: ###############" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W "# #. .####:#######" lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " ##### # :############" R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " #######################" 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " ############:#### %#####" EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " .#############:##% .## ." /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " %% .################. #. " ;s="v=%04o;ev"%
(;v=(v-($*+[45, ":####: :##############% : " ])[n=0].to_i;)%
360)+"al$s=%q#{ "%######. ######### " ;;"%c"%126+$s<<
126}";d.gsub!(/ "##########. #######% " |\s|".*"/,"");;
require"zlib"|| "########### :######. " ;d=d.unpack"C*"
d.map{|c|n=(n|| ":#########: .######: . " )*90+(c-2)%91};
e=["%x"%n].pack " :#######% :###### #: " &&"H*";e=Zlib::
Inflate.inflate( " ######% .####% :: " &&e).unpack("b*"
)[0];22.times{|y| " ####% %### " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .###: .#% " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "# :#######" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
</code></pre>
<p>This quine turns 45 degrees when executed; thus, it will come around when executed eight times (see below). You can make it any-degree turn by giving an integer as an command-line argument.</p>
<pre><code>v=0416;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC ".#####%.#% " 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B " .#####%##% :" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? " #####%###: #" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W " %######## #." lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " :####### ###" R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " ###: : ####" 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " %#... #####" EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " %### .#####" /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " :. %% .#####" ;s="v=%04o;ev"%
(;v=(v-($*+[45, " :####: :####" ])[n=0].to_i;)%
360)+"al$s=%q#{ " %######. " ;;"%c"%126+$s<<
126}";d.gsub!(/ " ##########. " |\s|".*"/,"");;
require"zlib"|| " ########### " ;d=d.unpack"C*"
d.map{|c|n=(n|| " :#########: " )*90+(c-2)%91};
e=["%x"%n].pack " :#######% " &&"H*";e=Zlib::
Inflate.inflate( " ######% " &&e).unpack("b*"
)[0];22.times{|y| " ####% " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .###: " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( " .##### :#" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0341;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "#% .#####%." 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B " : %#####%##. " O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? " #####%###: " g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W " %######## " lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " :####### " R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " :### : " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " %#... " EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " .###: " /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " :. %% " ;s="v=%04o;ev"%
(;v=(v-($*+[45, " :####: " ])[n=0].to_i;)%
360)+"al$s=%q#{ " %######. " ;;"%c"%126+$s<<
126}";d.gsub!(/ " ##########" |\s|".*"/,"");;
require"zlib"|| "% ##########" ;d=d.unpack"C*"
d.map{|c|n=(n|| " :#########" )*90+(c-2)%91};
e=["%x"%n].pack " ########" &&"H*";e=Zlib::
Inflate.inflate( "#. ######%" &&e).unpack("b*"
)[0];22.times{|y| "## :####. " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; "#. .###: " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ "% . %## " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " . #. " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " : " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "#. .##### " ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0264;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "####% .####" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "##### : .#####" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "######. #####%" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W "####: . %######" lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. "#### . :######" R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 "####% ###: " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ "### %#..." EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q "## .. %###" /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; ":#. . :" ;s="v=%04o;ev"%
(;v=(v-($*+[45, ": : : " ])[n=0].to_i;)%
360)+"al$s=%q#{ "% %#: " ;;"%c"%126+$s<<
126}";d.gsub!(/ "#::#.: %#% " |\s|".*"/,"");;
require"zlib"|| " : :#% " ;d=d.unpack"C*"
d.map{|c|n=(n|| " :% : " )*90+(c-2)%91};
e=["%x"%n].pack " %###%% " &&"H*";e=Zlib::
Inflate.inflate( " ########. " &&e).unpack("b*"
)[0];22.times{|y| " ########. " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " ##:%###. " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %% . " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " . " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "####. .###" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0207;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "#######% .#" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "##########: : " O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "#############. " g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W "############: . " lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. "############# . " R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 "############## " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ "# %######### " EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " %#: %##: : " /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " #. .:#. . " ;s="v=%04o;ev"%
(;v=(v-($*+[45, " : : : : " ])[n=0].to_i;)%
360)+"al$s=%q#{ " :% %#: " ;;"%c"%126+$s<<
126}";d.gsub!(/ " #::#.: %#% " |\s|".*"/,"");;
require"zlib"|| " : :#% " ;d=d.unpack"C*"
d.map{|c|n=(n|| " :% : " )*90+(c-2)%91};
e=["%x"%n].pack " .###%# " &&"H*";e=Zlib::
Inflate.inflate( " ########. " &&e).unpack("b*"
)[0];22.times{|y| " :######## " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " ##:%###. " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %% . " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " . " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "#######. ." ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0132;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC ":::#######%" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "################ : " O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "####################. " g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W " .####:############: . " lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. "# # :################# . " R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 "#######################% " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ "######:#### %######### " EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q "#######:##% .## .### .. " /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; "##########. #. .:#. . " ;s="v=%04o;ev"%
(;v=(v-($*+[45, "#########% : : : : " ])[n=0].to_i;)%
360)+"al$s=%q#{ "######### :% %#: " ;;"%c"%126+$s<<
126}";d.gsub!(/ "#######% #::#.: %#% " |\s|".*"/,"");;
require"zlib"|| ":######. : :#% " ;d=d.unpack"C*"
d.map{|c|n=(n|| ".######: . :% : " )*90+(c-2)%91};
e=["%x"%n].pack ":###### #: %###%% " &&"H*";e=Zlib::
Inflate.inflate( ".####% :: ########. " &&e).unpack("b*"
)[0];22.times{|y| " %### ########. " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .#% ##:%###. " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %% . " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " . " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "##########." ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0055;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "% :::#####" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B " .:################" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? " ######################" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W " #. .####:############: " lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " ##### # :################# . " R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " :############################ " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " ############:#### %######### " EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " %############:### %#: %##: : " /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " .################. #. .:#. . " ;s="v=%04o;ev"%
(;v=(v-($*+[45, " :##############% : : : : " ])[n=0].to_i;)%
360)+"al$s=%q#{ " ######### :% %#: " ;;"%c"%126+$s<<
126}";d.gsub!(/ " #######% #::#.: %#" |\s|".*"/,"");;
require"zlib"|| " :######. : :" ;d=d.unpack"C*"
d.map{|c|n=(n|| " .######: . :% " )*90+(c-2)%91};
e=["%x"%n].pack " ######%:# .###%" &&"H*";e=Zlib::
Inflate.inflate( " .####% :: ######" &&e).unpack("b*"
)[0];22.times{|y| " .###: :#####" ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .#% ##:%#" ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( ":##########" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0000;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "##% ::##########" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "##: ###############" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W "# #. .####:#######" lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " ##### # :############" R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " #######################" 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " ############:#### %#####" EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " .#############:##% .## ." /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " %% .################. #. " ;s="v=%04o;ev"%
(;v=(v-($*+[45, ":####: :##############% : " ])[n=0].to_i;)%
360)+"al$s=%q#{ "%######. ######### " ;;"%c"%126+$s<<
126}";d.gsub!(/ "##########. #######% " |\s|".*"/,"");;
require"zlib"|| "########### :######. " ;d=d.unpack"C*"
d.map{|c|n=(n|| ":#########: .######: . " )*90+(c-2)%91};
e=["%x"%n].pack " :#######% :###### #: " &&"H*";e=Zlib::
Inflate.inflate( " ######% .####% :: " &&e).unpack("b*"
)[0];22.times{|y| " ####% %### " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .###: .#% " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "# :#######" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
</code></pre>
<p>translated from <a href="http://d.hatena.ne.jp/ku-ma-me/20100905/p1">mamememo in Japanese (2010-09-05)</a>.</p>
<!--[markdown]
My Quines are sometimes specialized for Japanese. But to attend RubyConf, I should write "global" Quines.
v=0000;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "##% ::##########" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "##: ###############" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W "# #. .####:#######" lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " ##### # :############" R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " #######################" 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " ############:#### %#####" EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " .#############:##% .## ." /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " %% .################. #. " ;s="v=%04o;ev"%
(;v=(v-($*+[45, ":####: :##############% : " ])[n=0].to_i;)%
360)+"al$s=%q#{ "%######. ######### " ;;"%c"%126+$s<<
126}";d.gsub!(/ "##########. #######% " |\s|".*"/,"");;
require"zlib"|| "########### :######. " ;d=d.unpack"C*"
d.map{|c|n=(n|| ":#########: .######: . " )*90+(c-2)%91};
e=["%x"%n].pack " :#######% :###### #: " &&"H*";e=Zlib::
Inflate.inflate( " ######% .####% :: " &&e).unpack("b*"
)[0];22.times{|y| " ####% %### " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .###: .#% " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "# :#######" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
This quine turns 45 degrees when executed; thus, it will come around when executed eight times (see below). You can make it any-degree turn by giving an integer as an command-line argument.
v=0416;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC ".#####%.#% " 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B " .#####%##% :" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? " #####%###: #" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W " %######## #." lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " :####### ###" R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " ###: : ####" 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " %#... #####" EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " %### .#####" /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " :. %% .#####" ;s="v=%04o;ev"%
(;v=(v-($*+[45, " :####: :####" ])[n=0].to_i;)%
360)+"al$s=%q#{ " %######. " ;;"%c"%126+$s<<
126}";d.gsub!(/ " ##########. " |\s|".*"/,"");;
require"zlib"|| " ########### " ;d=d.unpack"C*"
d.map{|c|n=(n|| " :#########: " )*90+(c-2)%91};
e=["%x"%n].pack " :#######% " &&"H*";e=Zlib::
Inflate.inflate( " ######% " &&e).unpack("b*"
)[0];22.times{|y| " ####% " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .###: " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( " .##### :#" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0341;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "#% .#####%." 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B " : %#####%##. " O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? " #####%###: " g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W " %######## " lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " :####### " R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " :### : " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " %#... " EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " .###: " /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " :. %% " ;s="v=%04o;ev"%
(;v=(v-($*+[45, " :####: " ])[n=0].to_i;)%
360)+"al$s=%q#{ " %######. " ;;"%c"%126+$s<<
126}";d.gsub!(/ " ##########" |\s|".*"/,"");;
require"zlib"|| "% ##########" ;d=d.unpack"C*"
d.map{|c|n=(n|| " :#########" )*90+(c-2)%91};
e=["%x"%n].pack " ########" &&"H*";e=Zlib::
Inflate.inflate( "#. ######%" &&e).unpack("b*"
)[0];22.times{|y| "## :####. " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; "#. .###: " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ "% . %## " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " . #. " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " : " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "#. .##### " ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0264;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "####% .####" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "##### : .#####" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "######. #####%" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W "####: . %######" lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. "#### . :######" R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 "####% ###: " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ "### %#..." EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q "## .. %###" /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; ":#. . :" ;s="v=%04o;ev"%
(;v=(v-($*+[45, ": : : " ])[n=0].to_i;)%
360)+"al$s=%q#{ "% %#: " ;;"%c"%126+$s<<
126}";d.gsub!(/ "#::#.: %#% " |\s|".*"/,"");;
require"zlib"|| " : :#% " ;d=d.unpack"C*"
d.map{|c|n=(n|| " :% : " )*90+(c-2)%91};
e=["%x"%n].pack " %###%% " &&"H*";e=Zlib::
Inflate.inflate( " ########. " &&e).unpack("b*"
)[0];22.times{|y| " ########. " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " ##:%###. " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %% . " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " . " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "####. .###" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0207;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "#######% .#" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "##########: : " O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "#############. " g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W "############: . " lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. "############# . " R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 "############## " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ "# %######### " EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " %#: %##: : " /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " #. .:#. . " ;s="v=%04o;ev"%
(;v=(v-($*+[45, " : : : : " ])[n=0].to_i;)%
360)+"al$s=%q#{ " :% %#: " ;;"%c"%126+$s<<
126}";d.gsub!(/ " #::#.: %#% " |\s|".*"/,"");;
require"zlib"|| " : :#% " ;d=d.unpack"C*"
d.map{|c|n=(n|| " :% : " )*90+(c-2)%91};
e=["%x"%n].pack " .###%# " &&"H*";e=Zlib::
Inflate.inflate( " ########. " &&e).unpack("b*"
)[0];22.times{|y| " :######## " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " ##:%###. " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %% . " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " . " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "#######. ." ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0132;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC ":::#######%" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "################ : " O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "####################. " g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W " .####:############: . " lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. "# # :################# . " R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 "#######################% " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ "######:#### %######### " EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q "#######:##% .## .### .. " /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; "##########. #. .:#. . " ;s="v=%04o;ev"%
(;v=(v-($*+[45, "#########% : : : : " ])[n=0].to_i;)%
360)+"al$s=%q#{ "######### :% %#: " ;;"%c"%126+$s<<
126}";d.gsub!(/ "#######% #::#.: %#% " |\s|".*"/,"");;
require"zlib"|| ":######. : :#% " ;d=d.unpack"C*"
d.map{|c|n=(n|| ".######: . :% : " )*90+(c-2)%91};
e=["%x"%n].pack ":###### #: %###%% " &&"H*";e=Zlib::
Inflate.inflate( ".####% :: ########. " &&e).unpack("b*"
)[0];22.times{|y| " %### ########. " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .#% ##:%###. " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %% . " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " . " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "##########." ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0055;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "% :::#####" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B " .:################" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? " ######################" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W " #. .####:############: " lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " ##### # :################# . " R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " :############################ " 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " ############:#### %######### " EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " %############:### %#: %##: : " /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " .################. #. .:#. . " ;s="v=%04o;ev"%
(;v=(v-($*+[45, " :##############% : : : : " ])[n=0].to_i;)%
360)+"al$s=%q#{ " ######### :% %#: " ;;"%c"%126+$s<<
126}";d.gsub!(/ " #######% #::#.: %#" |\s|".*"/,"");;
require"zlib"|| " :######. : :" ;d=d.unpack"C*"
d.map{|c|n=(n|| " .######: . :% " )*90+(c-2)%91};
e=["%x"%n].pack " ######%:# .###%" &&"H*";e=Zlib::
Inflate.inflate( " .####% :: ######" &&e).unpack("b*"
)[0];22.times{|y| " .###: :#####" ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .#% ##:%#" ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( ":##########" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
v=0000;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "##% ::##########" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "##: ###############" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W "# #. .####:#######" lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " ##### # :############" R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " #######################" 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " ############:#### %#####" EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " .#############:##% .## ." /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " %% .################. #. " ;s="v=%04o;ev"%
(;v=(v-($*+[45, ":####: :##############% : " ])[n=0].to_i;)%
360)+"al$s=%q#{ "%######. ######### " ;;"%c"%126+$s<<
126}";d.gsub!(/ "##########. #######% " |\s|".*"/,"");;
require"zlib"|| "########### :######. " ;d=d.unpack"C*"
d.map{|c|n=(n|| ":#########: .######: . " )*90+(c-2)%91};
e=["%x"%n].pack " :#######% :###### #: " &&"H*";e=Zlib::
Inflate.inflate( " ######% .####% :: " &&e).unpack("b*"
)[0];22.times{|y| " ####% %### " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .###: .#% " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "# :#######" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
translated from [mamememo in Japanese (2010-09-05)](http://d.hatena.ne.jp/ku-ma-me/20100905/p1).
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com35tag:blogger.com,1999:blog-6309946718175890735.post-11899283131386543842010-08-30T20:54:00.006+09:002010-08-30T22:35:47.719+09:00RubyKaigi 2010<p>Long time no update!</p>
<p>I attended RubyKaigi 2010 at Tsukuba, Japan. It was really exciting!</p>
<p>I made a presentation, <a href="http://rubykaigi.org/2010/en/events/32">"Esoteric, Obfuscated Ruby Programming"</a>, which introduces esoteric programming with Ruby. Here is the presentation material:</p>
<ul>
<li><a href="http://dame.dyndns.org/misc/rubykaigi2010/rubykaigi2010-endoh.ppt">slide</a></li>
<li><a href="http://dame.dyndns.org/misc/rubykaigi2010/rubykaigi2010-endoh.zip">programs (zip)</a></li>
</ul>
<div style="width:425px" id="__ss_5088683"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/mametter/ruby-esoteric-obfuscated-ruby-programming-5088683" title="超絶技巧 Ruby プログラミング - Esoteric, Obfuscated Ruby Programming">超絶技巧 Ruby プログラミング - Esoteric, Obfuscated Ruby Programming</a></strong><object id="__sse5088683" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rubykaigi2010-endoh-100830083347-phpapp01&stripped_title=ruby-esoteric-obfuscated-ruby-programming-5088683" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5088683" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rubykaigi2010-endoh-100830083347-phpapp01&stripped_title=ruby-esoteric-obfuscated-ruby-programming-5088683" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/mametter">mametter</a>.</div></div>
<p>The slide is written in both Japanese and (weird) English.</p>
<p>Some programs will work on any platform, but some depends on Linux, gcc and its sound driver (/dev/dsp). If you cannot run them yourself, you can look <a href="http://www.nicovideo.jp/watch/sm11914507">my presentation movie</a> which includes demos (spoken in Japanese, but all the programs are written in Ruby, of course!).</p>
<p><script type="text/javascript" src="http://ext.nicovideo.jp/thumb_watch/sm11914507"></script><noscript><a href="http://www.nicovideo.jp/watch/sm11914507">【ニコニコ動画】[rk10][28M03] 超絶技巧 Ruby プログラミング</a></noscript></p>
<p>I appeared on stage three times in this RubyKaigi.</p>
<ul>
<li>committer Q&A, as a 1.9.2 assistant release manager. By questioning to the audience, I clarified the fact that many people wants core team to backport only security patches rather than new feature patches.</li>
<li>Matz's keynote, because I won "Ruby 1.9.2 Award" for contribution to ruby 1.9.2 release! I'm really proud of that.</li>
<li>my presentation, "Esoteric, Obfuscated Ruby Programming". It seemed to get a favorable reception, from some geeks :-)</li>
</ul>
<p>translated from <a href="http://d.hatena.ne.jp/ku-ma-me/20100829/p1">mamememo in Japanese (2010-08-29)</a>.</p>
<!--[markdown]
Long time no update!
I attended RubyKaigi 2010 at Tsukuba, Japan. It was really exciting!
I made a presentation, ["Esoteric, Obfuscated Ruby Programming"](http://rubykaigi.org/2010/en/events/32), which introduces esoteric programming with Ruby. Here is the presentation material:
- [slide](http://dame.dyndns.org/misc/rubykaigi2010/rubykaigi2010-endoh.ppt)
- [programs (zip)](http://dame.dyndns.org/misc/rubykaigi2010/rubykaigi2010-endoh.zip)
<div style="width:425px" id="__ss_5088683"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/mametter/ruby-esoteric-obfuscated-ruby-programming-5088683" title="超絶技巧 Ruby プログラミング - Esoteric, Obfuscated Ruby Programming">超絶技巧 Ruby プログラミング - Esoteric, Obfuscated Ruby Programming</a></strong><object id="__sse5088683" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rubykaigi2010-endoh-100830083347-phpapp01&stripped_title=ruby-esoteric-obfuscated-ruby-programming-5088683" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5088683" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rubykaigi2010-endoh-100830083347-phpapp01&stripped_title=ruby-esoteric-obfuscated-ruby-programming-5088683" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/mametter">mametter</a>.</div></div>
The slide is written in both Japanese and (weird) English.
Some programs will work on any platform, but some depends on Linux, gcc and its sound driver (/dev/dsp). If you cannot run them yourself, you can look [my presentation movie](http://www.nicovideo.jp/watch/sm11914507) which includes demos (spoken in Japanese, but all the programs are written in Ruby, of course!).
<script type="text/javascript" src="http://ext.nicovideo.jp/thumb_watch/sm11914507"></script><noscript><a href="http://www.nicovideo.jp/watch/sm11914507">【ニコニコ動画】[rk10][28M03] 超絶技巧 Ruby プログラミング</a></noscript>
I appeared on stage three times in this RubyKaigi.
- committer Q&A, as a 1.9.2 assistant release manager. By questioning to the audience, I clarified the fact that many people wants core team to backport only security patches rather than new feature patches.
- Matz's keynote, because I won "Ruby 1.9.2 Award" for contribution to ruby 1.9.2 release! I'm really proud of that.
- my presentation, "Esoteric, Obfuscated Ruby Programming". It seemed to get a favorable reception, from some geeks :-)
translated from [mamememo in Japanese (2010-08-29)](http://d.hatena.ne.jp/ku-ma-me/20100829/p1).
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com1tag:blogger.com,1999:blog-6309946718175890735.post-11606984321272625792009-12-24T19:28:00.002+09:002009-12-25T12:29:11.870+09:00Merry Quine-mas<pre><code>open("/dev/dsp","wb"){|h|s=%q{d=["-KQW[UZbgu*HNT+]TNOOOTZ+cZTUUUUUZbagmssUZbagm
ss+wmpgja+KQW[dfnu","-KEKOINV[W*HBH+QHBCCCHN+WNHIIIIINVU[aUUINVU[aUU+YOR[^I+KEK
OXZbW","-W[acg vsc*TZ`+eaaaaa--vucavuca+eadsvs+W[dgvrtc","-K991LIL77777dIIIII--
LKKILKKI+Mad[ ^U+K991LHJK"].map{|l|l.unpack("C*").map{|c|[(c/6-4)*12/7-8,"012
35b"[c%6,1]. hex]}*4};y=32.chr;l="@"+[(m="Jnx4sn3sgd1")+"vnqkc!6sgd2Lnqc4gz
r4bnld;6/Ld s2dzqsg6qd2@bdhud6gdq2Khmf;77/Lds2du4@dqx4gdzqs6oqd2@ozqd4ghl
4qnnl,+Amc 2gdz++2 @udm 4z mc 2gdz 4@+u dm 2zm
c2mz+@stqd+r hmf",m+"E zq sg !6sgd2Sz u4@h nt q4qd hfm r; 6/Ld
s2ldm6sgdhq 2rnmfr6d l 2 @o knx ;77/ Wghkd2 ehdkc
r4zmc4eknn cr,6qnb jr ,2 gh kkr,4zmc 4okz hm r+Rd 2@odz s+2+,6
qd2@odzs6 +sgd2r ntmc+@ hm f+ inx" ," Nn4l nqd3k ds1rhm
r6zmc2rn 4@qqnvr4fqnv,6/Nnq2sgnqmr6hm2@edrs6sgd2fqntmc;77/Hd2bnldr4
sn4lzjd 6Hhr2ak d4@rrh mfr4eknv+Fzq2zr+2+,6ezq2zr,6+sgd2btqr
d+hr+entmc ","Hd4qtkdr3s gd1 vnqkc6vhsg2sqtsg4zmc4fqzbd,6/Amc2lzjdr6
sgd2mz6@s hnmr2oqnud77/ T gd2fk n4@q hdr4 ne6Hh r2qhfg
s4@dntr4 @mdrr,+Amc2v nm+2+6@ cd qr, 2v nm6 +@cdqr2ne+Hh
r+knud" ].map{|a| a ,b,c,e, * f =a. sp lit" +";[a,c
=b+c+f *"2",c ,b+ e+f*"4 "+ ". 8/ /"]*"6/" }.join
.tr(" a-z /","b- za\ n").gs ub (/^/ ," #"<<32)
;c=0;640.tim es{|w|c<1&&(l=~/(@)?(.*?)(\d)/m;($>.<<$1?$2:y+$2).flush;l=$';c
=eval$3);c-= 1;a=[128]*z=1200;4.times{|j|t,n=d[j].pop;f=0.3456*2**(t/12.0-j
/2);(n>0?(d[ j]<<[t,n-1];z):800).times{|i|t>-3&&a[i]+=16*Math.sin(f.*w*z+i)
}};(h.<<a.pack"C*").flush};puts(s.gsub(/./){"!">$&?"#":y}+%(\nopen("/dev/dsp#{"
(c)Y.Endoh2009";'",'}"wb"){|h|s=%q{#{s}};eval(s.split*"")}))};eval(s.split*"")}
</code></pre>
<p>Run it under environment where /dev/dsp is available. If you are windows user, you can use cygwin.
It often abends on cygwin. Please re-run it until it works.</p>
<p>The structure of the program:</p>
<ul>
<li>Lines 1-4: encoded musical score data</li>
<li>Lines 4-5: score decoder</li>
<li>Lines 5-17: crypted compressed lyrics data (with timing data)</li>
<li>Lines 17-19: lyrics decompressor</li>
<li>Lines 20-21: lyrics player</li>
<li>Lines 21-23: wave synthesizer</li>
<li>Lines 23-24: quine</li>
</ul>
<p>translated from <a href="http://d.hatena.ne.jp/ku-ma-me/20091224/p1">mamememo in Japanese (2009-12-24)</a>.</p>
<!--[markdown]
open("/dev/dsp","wb"){|h|s=%q{d=["-KQW[UZbgu*HNT+]TNOOOTZ+cZTUUUUUZbagmssUZbagm
ss+wmpgja+KQW[dfnu","-KEKOINV[W*HBH+QHBCCCHN+WNHIIIIINVU[aUUINVU[aUU+YOR[^I+KEK
OXZbW","-W[acg vsc*TZ`+eaaaaa--vucavuca+eadsvs+W[dgvrtc","-K991LIL77777dIIIII--
LKKILKKI+Mad[ ^U+K991LHJK"].map{|l|l.unpack("C*").map{|c|[(c/6-4)*12/7-8,"012
35b"[c%6,1]. hex]}*4};y=32.chr;l="@"+[(m="Jnx4sn3sgd1")+"vnqkc!6sgd2Lnqc4gz
r4bnld;6/Ld s2dzqsg6qd2@bdhud6gdq2Khmf;77/Lds2du4@dqx4gdzqs6oqd2@ozqd4ghl
4qnnl,+Amc 2gdz++2 @udm 4z mc 2gdz 4@+u dm 2zm
c2mz+@stqd+r hmf",m+"E zq sg !6sgd2Sz u4@h nt q4qd hfm r; 6/Ld
s2ldm6sgdhq 2rnmfr6d l 2 @o knx ;77/ Wghkd2 ehdkc
r4zmc4eknn cr,6qnb jr ,2 gh kkr,4zmc 4okz hm r+Rd 2@odz s+2+,6
qd2@odzs6 +sgd2r ntmc+@ hm f+ inx" ," Nn4l nqd3k ds1rhm
r6zmc2rn 4@qqnvr4fqnv,6/Nnq2sgnqmr6hm2@edrs6sgd2fqntmc;77/Hd2bnldr4
sn4lzjd 6Hhr2ak d4@rrh mfr4eknv+Fzq2zr+2+,6ezq2zr,6+sgd2btqr
d+hr+entmc ","Hd4qtkdr3s gd1 vnqkc6vhsg2sqtsg4zmc4fqzbd,6/Amc2lzjdr6
sgd2mz6@s hnmr2oqnud77/ T gd2fk n4@q hdr4 ne6Hh r2qhfg
s4@dntr4 @mdrr,+Amc2v nm+2+6@ cd qr, 2v nm6 +@cdqr2ne+Hh
r+knud" ].map{|a| a ,b,c,e, * f =a. sp lit" +";[a,c
=b+c+f *"2",c ,b+ e+f*"4 "+ ". 8/ /"]*"6/" }.join
.tr(" a-z /","b- za\ n").gs ub (/^/ ," #"<<32)
;c=0;640.tim es{|w|c<1&&(l=~/(@)?(.*?)(\d)/m;($>.<<$1?$2:y+$2).flush;l=$';c
=eval$3);c-= 1;a=[128]*z=1200;4.times{|j|t,n=d[j].pop;f=0.3456*2**(t/12.0-j
/2);(n>0?(d[ j]<<[t,n-1];z):800).times{|i|t>-3&&a[i]+=16*Math.sin(f.*w*z+i)
}};(h.<<a.pack"C*").flush};puts(s.gsub(/./){"!">$&?"#":y}+%(\nopen("/dev/dsp#{"
(c)Y.Endoh2009";'",'}"wb"){|h|s=%q{#{s}};eval(s.split*"")}))};eval(s.split*"")}
Run it under environment where /dev/dsp is available. If you are windows user, you can use cygwin.
It often abends on cygwin. Please re-run it until it works.
The structure of the program:
- Lines 1-4: encoded musical score data
- Lines 4-5: score decoder
- Lines 5-17: crypted compressed lyrics data (with timing data)
- Lines 17-19: lyrics decompressor
- Lines 20-21: lyrics player
- Lines 21-23: wave synthesizer
- Lines 23-24: quine
translated from [mamememo in Japanese (2009-12-24)](http://d.hatena.ne.jp/ku-ma-me/20091224/p1).
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com3tag:blogger.com,1999:blog-6309946718175890735.post-3967945791493974442009-11-17T00:31:00.007+09:002009-11-17T00:44:47.288+09:00qng and qif: self-reproducing images<h3>qng image</h3>
<p><img src="http://dame.dyndns.org/misc/misc/qng.png" alt="http://dame.dyndns.org/misc/misc/qng.png" title="" /></p>
<p>The above image is <em>qng</em>, a png image that prints a Ruby script that generates the image itself.</p>
<pre><code>$ cat qng.rb
eval s=%q(require"zlib";include Zlib;f=Inflate.inflate(*"eNq
1VomxQyEIpAP675IOiAjqIvqS/INh3hh1dTkN0c+FOfR5j6r4Nh98cT6xSIf
Yl4WEfi92mn1Q7WCOxRijCiXWjUfjo/Y9MBLTZqkP3sh2chfDfiKSrxxUcRg
Wa6dsfMUHbSZxkAAGHFYd202KM5EerlI9uQHU4i499MPXy0yJA0/YdR1Vzp3
DbjIVe/mEhclA8rdpJU/hexb33qch/hNxK71Uh+3AJ2ZwUHw1UyNHwX6P1LI
SJTQL4yslc+qq0OleFggW1F9QlTlGLN3zmVS2ZbTXrZCezjKsy45MqoWVsmk
I+rktkSxh05qTU3O2Y4xuvppRSL6q8d185X7mUw2uJoZaonDkvCb9gajY6Yn
yiEyg5+3GOV1XWK3OIHu/Yt37eqiu4K7nIP3oe07glFr/KR4g1lQLkIdYFBW
7ShhyI+ZYMYJS7x2FBtj2jnt3zy49YrHZsp45S04Ow16yLq4p4dD0pvek8qY
3wCynAi5tWBmrVEr3vnA+2EsP2FnIOUbJV+mBV2sgF8oRX8+Q1L1Heq8Alfj
m+j2vrhKuq1DCdRVL+N29pfOMEl49lqGlY/bzpTuDv/b9cvjbcJMXSB2OYQ=
=".unpack("m"));z="\0";s="IDAT"+Deflate.deflate(z*561+%(eva\
l s=%q(#{s})).scan(/.+/).map{|l|(0..9).map{|i|[z*4,l.bytes .
map{|c|f[c*30+i*3-960,3]},z*3]}*""}*(z*187)+z*561);print ["\
\x89PNG\r\n\x1a\n","\rIHDR",372,192,4,0,4107545177,s.size-4,
s,Zlib.crc32(s),0,"IEND\xAEB\x60\x82"].pack"a11A*NNCN3A*NNA*
"############## qng.rb (c) Yusuke Endoh 2009 ##############)
$ ruby qng.rb > qng.png
</code></pre>
<h3>qif image</h3>
<p><img src="http://dame.dyndns.org/misc/misc/qif.gif" alt="http://dame.dyndns.org/misc/misc/qif.gif" title="" /></p>
<p>The above image is <em>qif</em>, a gif image that prints a Ruby script that generates the image itself.</p>
<pre><code>$ cat qif.rb
Y,E=%q~260|0!e0*h0($0j0($"!e0($"f0e0($0!e0*p;4f4#.q9!&8*%"1(
}+0!,e4|8,e<.%}e6#g4*};!(4*%})2!e09$"u91&(#6}f0(%+#u0)6"1(7,
v0.,*%"<8{9!(4+2}!(4*%90}<.'#<(}$"!e0($")n48$6!(0($".!e0($"$
e0w0($")k0r4*%"<8$"!9!&8*%"<0|0($"#&0()0i;f=87$};!(4+6"!e0j;
f0(',}91(4+3e0($j;!.8)2}}}}}}},4"!e0($"!2i2!i0)e0e0(#$0($"!e
0(,0}}o0(%2"1(4~,%~y;0('&!e=8}}q9!($"!"<0}}}}}}y0g4f0+2}441$
!}g;0&<}h2$11!{0!q0}h0m0|20!&8*%9s9!(7$%"<0p0!e4"g3.q9!(7&!(
(0o9!(3&!e=8o0(&>#01(t9!(2$$"<0o;0*"$$"<0o9e0($")e0o9!(4.%"<
0n4"g0*!h0(o0}}k;0{0!}}g0+."!}f0?$'!t0!($"!e0e2i0e2!e0($f4}t
0($k=!-%%!040r70&8!;}%3#,0/,"r8->#!78}z8,&s0g0($"!g~;eval$s=
%q(h=eval"0b"+(Y+"}"*39+E).bytes.map{|x|x<95?("%05b".%x-32if
32<x):"0"*(x-96)}*"";z=[2,128].pack"vC";print [71,73,70,"89\
a",372,192,736,0,0,65535,11519,0,0,372,192,768,z*372,%(Y,E=\
%q~#{Y}~,%~#{E}~;eval$s=\n%q(#$s)).scan(/.+/).map{|l|(0..9).
map{|i|[z*2,l.bytes.map{|c|[4,17&n=h>>60*c-1980+i*6,17&n>>1,
n[2]+n[3]*16,136].pack "C*"},z*2]}*""}*(z*124),z*372,"\0;"].
pack"C3a3v12"+"a*"*4 #### qif.rb (c) Yusuke Endoh 2009 ####)
$ ruby qif.rb > qif.gif
</code></pre>
<h3>COPYRIGHTS</h3>
<p>The two images contain <a href="http://www.proggyfonts.com/">Proggy Programming Fonts</a>:</p>
<pre><code>Copyright (c) 2004, 2005 Tristan Grimmer
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</code></pre>
<p>translated from <a href="http://d.hatena.ne.jp/ku-ma-me/20090723/p1">mamememo in Japanese (2009-07-23)</a> and <a href="http://d.hatena.ne.jp/ku-ma-me/20091116/p1">(2009-11-16)</a>.</p>
<!--[markdown]
### qng image
![http://dame.dyndns.org/misc/misc/qng.png](http://dame.dyndns.org/misc/misc/qng.png)
The above image is *qng*, a png image that prints a Ruby script that generates the image itself.
$ cat qng.rb
eval s=%q(require"zlib";include Zlib;f=Inflate.inflate(*"eNq
1VomxQyEIpAP675IOiAjqIvqS/INh3hh1dTkN0c+FOfR5j6r4Nh98cT6xSIf
Yl4WEfi92mn1Q7WCOxRijCiXWjUfjo/Y9MBLTZqkP3sh2chfDfiKSrxxUcRg
Wa6dsfMUHbSZxkAAGHFYd202KM5EerlI9uQHU4i499MPXy0yJA0/YdR1Vzp3
DbjIVe/mEhclA8rdpJU/hexb33qch/hNxK71Uh+3AJ2ZwUHw1UyNHwX6P1LI
SJTQL4yslc+qq0OleFggW1F9QlTlGLN3zmVS2ZbTXrZCezjKsy45MqoWVsmk
I+rktkSxh05qTU3O2Y4xuvppRSL6q8d185X7mUw2uJoZaonDkvCb9gajY6Yn
yiEyg5+3GOV1XWK3OIHu/Yt37eqiu4K7nIP3oe07glFr/KR4g1lQLkIdYFBW
7ShhyI+ZYMYJS7x2FBtj2jnt3zy49YrHZsp45S04Ow16yLq4p4dD0pvek8qY
3wCynAi5tWBmrVEr3vnA+2EsP2FnIOUbJV+mBV2sgF8oRX8+Q1L1Heq8Alfj
m+j2vrhKuq1DCdRVL+N29pfOMEl49lqGlY/bzpTuDv/b9cvjbcJMXSB2OYQ=
=".unpack("m"));z="\0";s="IDAT"+Deflate.deflate(z*561+%(eva\
l s=%q(#{s})).scan(/.+/).map{|l|(0..9).map{|i|[z*4,l.bytes .
map{|c|f[c*30+i*3-960,3]},z*3]}*""}*(z*187)+z*561);print ["\
\x89PNG\r\n\x1a\n","\rIHDR",372,192,4,0,4107545177,s.size-4,
s,Zlib.crc32(s),0,"IEND\xAEB\x60\x82"].pack"a11A*NNCN3A*NNA*
"############## qng.rb (c) Yusuke Endoh 2009 ##############)
$ ruby qng.rb > qng.png
### qif image
![http://dame.dyndns.org/misc/misc/qif.gif](http://dame.dyndns.org/misc/misc/qif.gif)
The above image is *qif*, a gif image that prints a Ruby script that generates the image itself.
$ cat qif.rb
Y,E=%q~260|0!e0*h0($0j0($"!e0($"f0e0($0!e0*p;4f4#.q9!&8*%"1(
}+0!,e4|8,e<.%}e6#g4*};!(4*%})2!e09$"u91&(#6}f0(%+#u0)6"1(7,
v0.,*%"<8{9!(4+2}!(4*%90}<.'#<(}$"!e0($")n48$6!(0($".!e0($"$
e0w0($")k0r4*%"<8$"!9!&8*%"<0|0($"#&0()0i;f=87$};!(4+6"!e0j;
f0(',}91(4+3e0($j;!.8)2}}}}}}},4"!e0($"!2i2!i0)e0e0(#$0($"!e
0(,0}}o0(%2"1(4~,%~y;0('&!e=8}}q9!($"!"<0}}}}}}y0g4f0+2}441$
!}g;0&<}h2$11!{0!q0}h0m0|20!&8*%9s9!(7$%"<0p0!e4"g3.q9!(7&!(
(0o9!(3&!e=8o0(&>#01(t9!(2$$"<0o;0*"$$"<0o9e0($")e0o9!(4.%"<
0n4"g0*!h0(o0}}k;0{0!}}g0+."!}f0?$'!t0!($"!e0e2i0e2!e0($f4}t
0($k=!-%%!040r70&8!;}%3#,0/,"r8->#!78}z8,&s0g0($"!g~;eval$s=
%q(h=eval"0b"+(Y+"}"*39+E).bytes.map{|x|x<95?("%05b".%x-32if
32<x):"0"*(x-96)}*"";z=[2,128].pack"vC";print [71,73,70,"89\
a",372,192,736,0,0,65535,11519,0,0,372,192,768,z*372,%(Y,E=\
%q~#{Y}~,%~#{E}~;eval$s=\n%q(#$s)).scan(/.+/).map{|l|(0..9).
map{|i|[z*2,l.bytes.map{|c|[4,17&n=h>>60*c-1980+i*6,17&n>>1,
n[2]+n[3]*16,136].pack "C*"},z*2]}*""}*(z*124),z*372,"\0;"].
pack"C3a3v12"+"a*"*4 #### qif.rb (c) Yusuke Endoh 2009 ####)
$ ruby qif.rb > qif.gif
### COPYRIGHTS
The two images contain [Proggy Programming Fonts](http://www.proggyfonts.com/):
Copyright (c) 2004, 2005 Tristan Grimmer
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
translated from [mamememo in Japanese (2009-07-23)](http://d.hatena.ne.jp/ku-ma-me/20090723/p1) and [(2009-11-16)](http://d.hatena.ne.jp/ku-ma-me/20091116/p1).
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com0tag:blogger.com,1999:blog-6309946718175890735.post-43272892769905628932009-11-15T04:02:00.002+09:002009-11-15T04:06:47.817+09:00_ : a library that allows you to write Ruby script by using only _<p>I published one of my darling libraries into gemcutter, named <strong>_</strong>. By using _, you can write Ruby script that consist only of _.</p>
<h3>Getting started</h3>
<pre><code>$ gem install _
</code></pre>
<p>Source code: <a href="http://github.com/mame/_">http://github.com/mame/_</a></p>
<p>Gem info: <a href="http://gemcutter.org/gems/_">http://gemcutter.org/gems/_</a></p>
<h3>Example</h3>
<p>This is "Hello, world!" __script__ written in Ruby:</p>
<pre name="code" class="ruby">
require "_"
____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______
_____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _
____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____
__ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
</pre>
<p>This is nothing but normal Ruby __script__. Works on Ruby 1.8 and 1.9. You can rearrenge line breaks but can not change the order of _s.</p>
<pre><code>$ ruby18 -rubygems __hello__.rb
Hello, world!
$ ruby19 __hello__.rb
Hello, world!
</code></pre>
<p>If you mind the first `require' line, the option `-r_' can be used in Ruby 1.9.</p>
<pre><code>$ ruby19 -r_ -e '____ _ _____ ____ __ ____ ____ __ ___ ____ __
__ _ ______ _____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _
____ _ ____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____
____ __ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
'
Hello, world!
</code></pre>
<p>And, you can translate your own script into __script__ by __script__ method.</p>
<pre><code>$ echo -n 'puts"Hello, world!"' | ruby19 -r_ -e 'puts __script__($<.read)'
require "_"
____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______
_____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _
____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____
__ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
</code></pre>
<p>translated from <a href="http://d.hatena.ne.jp/ku-ma-me/20090402/p1">mamememo in Japanese (2009-04-02)</a> and <a href="http://d.hatena.ne.jp/ku-ma-me/20091115/p1">(2009-11-15)</a>.</p>
<!--[markdown]
I published one of my darling libraries into gemcutter, named **\_**. By using \_, you can write Ruby script that consist only of \_.
### Getting started
$ gem install _
Source code: [http://github.com/mame/_](http://github.com/mame/_)
Gem info: [http://gemcutter.org/gems/_](http://gemcutter.org/gems/_)
### Example
This is "Hello, world!" \_\_script\_\_ written in Ruby:
<pre name="code" class="ruby">
require "_"
____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______
_____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _
____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____
__ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
</pre>
This is nothing but normal Ruby \_\_script\_\_. Works on Ruby 1.8 and 1.9. You can rearrenge line breaks but can not change the order of \_s.
$ ruby18 -rubygems __hello__.rb
Hello, world!
$ ruby19 __hello__.rb
Hello, world!
If you mind the first \`require' line, the option \`-r\_' can be used in Ruby 1.9.
$ ruby19 -r_ -e '____ _ _____ ____ __ ____ ____ __ ___ ____ __
__ _ ______ _____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _
____ _ ____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____
____ __ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
'
Hello, world!
And, you can translate your own script into \_\_script\_\_ by \_\_script\_\_ method.
$ echo -n 'puts"Hello, world!"' | ruby19 -r_ -e 'puts __script__($<.read)'
require "_"
____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______
_____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _
____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____
__ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
translated from [mamememo in Japanese (2009-04-02)](http://d.hatena.ne.jp/ku-ma-me/20090402/p1) and [(2009-11-15)](http://d.hatena.ne.jp/ku-ma-me/20091115/p1).
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com0tag:blogger.com,1999:blog-6309946718175890735.post-59199096193526146092009-11-11T21:46:00.003+09:002009-11-12T02:54:36.831+09:00enumerabler.rb: Enumerable lazy-version method library<p>When you want to gather first ten even numbers from an integer array, what do you do?</p>
<pre name="code" class="ruby">
ary.select {|x| x.even? }.take(10)
</pre>
<p>The above program is very simple. But it may cause a lot of unnecessary checks when array is big. Also, `select' creates intermediate array.</p>
<pre name="code" class="ruby">
ret = []
ary.each do |x|
ret << x if x.even?
break if ret.size == 10
end
</pre>
<p>This will stop the loop when enough even numbers is found, and create no unnecessary array. But, it has trouble with readability and maintainability because it is very dirty, cumbersome, tricky, too long and too primitive. We live in the age of Ruby 1.9. We need <strong>more elegance</strong>.</p>
<h3>"We can use Enumerator and `to_enum' in Ruby 1.9!"</h3>
<p>It's a good idea, but you are unfortunate.</p>
<pre name="code" class="ruby">
(1..50).to_enum(:select) {|x| x.even? }.take(10)
#=> [1,2,3,4,5,6,7,8,9,10] # never selected!
</pre>
<p>Please think yourself the reason why it does not work. `to_enum' is too difficult for me, to explain in English :-p</p>
<p>No matter how you combine `to_enum' and `select', it will never work, I guess.
You can (must) use Enumerator.new without using Enumearble#select:</p>
<pre name="code" class="ruby">
module Enumerable
def selector(&blk)
Enumerator.new do |e|
each do |x|
e << x if blk[x]
end
end
end
end
</pre>
<p>Also troublesome...</p>
<h3>proposed `enumerabler.rb'</h3>
<p>I wrote a library, named <em>enumerabler.rb</em>, which is a collection of the above method definitions.</p>
<pre name="code" class="ruby">
require "enumerabler"
ary.selector {|x| x.even? }.take(10)
</pre>
<p>You use `selector' instead of `select.' While `select' returns an array, `selector' returns an Enumerator corresponding the array. Because of Enumerator, the evaluation is delayed. So, the above program using `selector' is not only simple but also effective, which will stop its loop as soon as ten even numbers is found. No intermediate array.</p>
<p>enumerabler.rb defines:</p>
<ul>
<li>Enumerable#grepper</li>
<li>Enumerable#finder_all (alias: all_finder, selector)</li>
<li>Enumerable#rejecter</li>
<li>Enumerable#collector (alias: mapper)</li>
<li>Enumerable#flat_mapper (alias: concat_collector)</li>
<li>Enumerable#zipper</li>
<li>Enumerable#taker</li>
<li>Enumerable#taker_while</li>
<li>Enumerable#dropper</li>
<li>Enumerable#dropper_while</li>
</ul>
<p>All of them returns corresponding Enumerator.
In an aside, I cannot distinguish -er and -or without a dictionary.</p>
<h3>"Does it use a Fiber? Isn't it slow?"</h3>
<p>No, enumerabler.rb does neither generate nor yield a Fiber. Trust me. If you worry, please read and check the source code of Ruby!</p>
<p>However, it is actually slow because it calls Proc frequently. `selector' is about two or three times slower than the original `select', but it is faster than a Fiber, and actually reduces memory usage.</p>
<h3>Examples</h3>
<pre name="code" class="ruby">
p ary.selector {|x| x.even? }.taker(100).take_while {|x| x >= 0 }
</pre>
<p>gathers first 100 even numbers, however terminates before the negative element, without unnecessary check and intermediate array.</p>
<pre name="code" class="ruby">
require "enumerabler"
def sieve(e, &blk)
yield n = e.first
sieve(e.rejecter {|x| x % n == 0 }, &blk)
end
sieve(2..(1.0/0.0)) {|x| p x } #=> 2, 3, 5, 7, 11, 13, 17, 19, 23, ...
</pre>
<p>Sieve of Eratosthenes using `rejecter.'</p>
<pre name="code" class="ruby">
require "enumerabler"
def fibonacci
Enumerator.new do |e|
e << 1
e << 1
fibonacci.zip(fibonacci.dropper(1)) {|x, y| e << x + y }
end
end
fibonacci.each {|x| p x } #=> 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
</pre>
<p>Fibonacci numbers. `dropper' can drop an infinite sequence. Note that this is very slow because of call-by-name evaluation and because `zip' internally uses a Fiber.</p>
<h3>how to install</h3>
<pre><code>$ gem install enumerabler
</code></pre>
<p><a href="http://github.com/mame/enumerabler">http://github.com/mame/enumerabler</a></p>
<p>translated from <a href="http://d.hatena.ne.jp/ku-ma-me/20091111/p2">mamememo in Japanese (2009-11-11)</a>.</p>
<!--[markdown]
When you want to gather first ten even numbers from an integer array, what do you do?
<pre name="code" class="ruby">
ary.select {|x| x.even? }.take(10)
</pre>
The above program is very simple. But it may cause a lot of unnecessary checks when array is big. Also, `select' creates intermediate array.
<pre name="code" class="ruby">
ret = []
ary.each do |x|
ret << x if x.even?
break if ret.size == 10
end
</pre>
This will stop the loop when enough even numbers is found, and create no unnecessary array. But, it has trouble with readability and maintainability because it is very dirty, cumbersome, tricky, too long and too primitive. We live in the age of Ruby 1.9. We need **more elegance**.
### "We can use Enumerator and `to\_enum' in Ruby 1.9!"
It's a good idea, but you are unfortunate.
<pre name="code" class="ruby">
(1..50).to_enum(:select) {|x| x.even? }.take(10)
#=> [1,2,3,4,5,6,7,8,9,10] # never selected!
</pre>
Please think yourself the reason why it does not work. \`to\_enum' is too difficult for me, to explain in English :-p
No matter how you combine \`to\_enum' and \`select', it will never work, I guess.
You can (must) use Enumerator.new without using Enumearble#select:
<pre name="code" class="ruby">
module Enumerable
def selector(&blk)
Enumerator.new do |e|
each do |x|
e << x if blk[x]
end
end
end
end
</pre>
Also troublesome...
### proposed \`enumerabler.rb'
I wrote a library, named *enumerabler.rb*, which is a collection of the above method definitions.
<pre name="code" class="ruby">
require "enumerabler"
ary.selector {|x| x.even? }.take(10)
</pre>
You use \`selector' instead of \`select.' While \`select' returns an array, \`selector' returns an Enumerator corresponding the array. Because of Enumerator, the evaluation is delayed. So, the above program using \`selector' is not only simple but also effective, which will stop its loop as soon as ten even numbers is found. No intermediate array.
enumerabler.rb defines:
- Enumerable#grepper
- Enumerable#finder\_all (alias: all\_finder, selector)
- Enumerable#rejecter
- Enumerable#collector (alias: mapper)
- Enumerable#flat\_mapper (alias: concat\_collector)
- Enumerable#zipper
- Enumerable#taker
- Enumerable#taker\_while
- Enumerable#dropper
- Enumerable#dropper\_while
All of them returns corresponding Enumerator.
In an aside, I cannot distinguish -er and -or without a dictionary.
### "Does it use a Fiber? Isn't it slow?"
No, enumerabler.rb does neither generate nor yield a Fiber. Trust me. If you worry, please read and check the source code of Ruby!
However, it is actually slow because it calls Proc frequently. \`selector' is about two or three times slower than the original \`select', but it is faster than a Fiber, and actually reduces memory usage.
### Examples
<pre name="code" class="ruby">
p ary.selector {|x| x.even? }.taker(100).take_while {|x| x >= 0 }
</pre>
gathers first 100 even numbers, however terminates before the negative element, without unnecessary check and intermediate array.
<pre name="code" class="ruby">
require "enumerabler"
def sieve(e, &blk)
yield n = e.first
sieve(e.rejecter {|x| x % n == 0 }, &blk)
end
sieve(2..(1.0/0.0)) {|x| p x } #=> 2, 3, 5, 7, 11, 13, 17, 19, 23, ...
</pre>
Sieve of Eratosthenes using \`rejecter.'
<pre name="code" class="ruby">
require "enumerabler"
def fibonacci
Enumerator.new do |e|
e << 1
e << 1
fibonacci.zip(fibonacci.dropper(1)) {|x, y| e << x + y }
end
end
fibonacci.each {|x| p x } #=> 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
</pre>
Fibonacci numbers. \`dropper' can drop an infinite sequence. Note that this is very slow because of call-by-name evaluation and because \`zip' internally uses a Fiber.
### how to install
$ gem install enumerabler
[http://github.com/mame/enumerabler](http://github.com/mame/enumerabler)
translated from [mamememo in Japanese (2009-11-11)](http://d.hatena.ne.jp/ku-ma-me/20091111/p2).
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.comtag:blogger.com,1999:blog-6309946718175890735.post-66665509407538340052009-10-08T03:58:00.003+09:002009-10-08T04:08:17.841+09:00Piet Quine<p><center><img src="http://dame.dyndns.org/misc/piet/quine.gif" alt="Piet Quine (c) Y.Endoh" title="" /></center></p>
<pre><code>$ ../npiet-1.1/npiet quine.gif > quine2.gif
$ diff quine.gif quine2.gif
</code></pre>
<p>translated (?) from <a href="http://d.hatena.ne.jp/ku-ma-me/20091006/p1">mamememo in Japanese (2009-10-06)</a>.</p>
<!--[markdown]
<center>![Piet Quine (c) Y.Endoh](http://dame.dyndns.org/misc/piet/quine.gif)</center>
$ ../npiet-1.1/npiet quine.gif > quine2.gif
$ diff quine.gif quine2.gif
translated (?) from [mamememo in Japanese (2009-10-06)](http://d.hatena.ne.jp/ku-ma-me/20091006/p1).
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com4tag:blogger.com,1999:blog-6309946718175890735.post-51032426939856701202009-10-06T00:36:00.010+09:002009-10-08T04:04:35.190+09:00Piet is Turing-complete<p>I proved Turing-completeness of <a href="http://www.dangermouse.net/esoteric/piet.html">the programming language Piet</a> by defining a translation from brainfuck to Piet.</p>
<h3>translation approach</h3>
<h4>1. Correspond brainfuck's tape and piet's stack.</h4>
<ul>
<li>The top of the piet's stack must equal to the value that the brainfuck's pointer indicates.</li>
<li>The second top must equal to current index of pointer, plus 3.</li>
<li>The third top must equal to total length of the whole tape, plus 3.</li>
<li>The remain part of the stack must equal to data of type except the value on the current pointer.</li>
</ul>
<p>For example, the following brainfuck's tape:</p>
<pre><code>+---+---+---+---+---+---+
| A | B | C | D | E | F |
+---+---+---+---+---+---+
^
pointer
</code></pre>
<p>corresponds to the following piet's stack:</p>
<pre><code>(top) D 6 9 A B C E F (bottom)
where 6 is current index of pointer + 3
9 is total length of tape + 3
</code></pre>
<h4>2. Define auxiliary functions.</h4>
<p>pick(n): push the n-th top value of the stack.</p>
<pre><code>(top) A B C D E F (bottom)
|
| pick(3)
v
(top) D A B C D E F (bottom)
</code></pre>
<p>deposit: insert the top value to the n-th index</p>
<pre><code>(top) D 6 9 A B C E F (bottom)
|
| deposit
v
(top) 6 9 A B C D E F (bottom)
</code></pre>
<p>withdraw: pull the n-th value to the top (inversion of deposit)</p>
<pre><code>(top) 5 9 A B C D E F (bottom)
|
| withdraw
v
(top) C 5 9 A B D E F (bottom)
</code></pre>
<p>definitions:</p>
<pre><code>pick(0) = dup
pick(n) = push(n+1); push(-1); roll; dup; push(n+2); push(1); roll
deposit: pick(1); push(1); roll
withdraw: dup; push(-1); roll
</code></pre>
<h4>3. Put initializer of the piet's stack.</h4>
<p>initial state of the stack:</p>
<pre><code>(top) 0 3 3 (bottom)
</code></pre>
<h4>4. Put piet's instractions correspoinding to each brainfuck's instruction.</h4>
<pre><code>+: push(1); add
-: push(1); sub
>: deposit
if (the second top value) > (top value)
# extend tape
# (top) 9 9 A B C D E F (bottom)
# |
# | extend
# v
# (top) 0 10 10 A B C D E F (bottom)
pop; push(1); add; dup; push(0)
else
push(1); iadd; withdraw
end
<: deposit; push(1); sub; withdraw
[: if (top value) * 2 <= 0
jump the corresponding ']'
end
]: jump the corresponding '['
,: pop; in(char)
.: dup; out(char)
</code></pre>
<p>Of course, branches and jumps are represented by "greater", "switch" and "pointer".
Note that the piet's stack is not required to hold arbitrarily long number.</p>
<h4>5. Put a terminator of execution.</h4>
<p>See <a href="http://www.dangermouse.net/esoteric/piet.html">Piet Speficication</a>.</p>
<h3>full implementation</h3>
<p><a href="http://github.com/mame/piet-misc/blob/master/bf2piet.rb">http://github.com/mame/piet-misc/blob/master/bf2piet.rb</a></p>
<h3>example</h3>
<p>An echo program written in brainfuck</p>
<pre><code>,[.,]
</code></pre>
<p>is translated to the following Piet program:</p>
<pre><code>$ ruby19 bf2piet.rb echo.bf > echo.piet.png
</code></pre>
<p><img src="http://dame.dyndns.org/misc/piet/echo.piet.png" alt="echo.piet.png" title="" /></p>
<p>You can see ',', '[', '.', ',' and ']' above each corresponding sequence of instructions. </p>
<pre><code>$ echo foobar | ../npiet-1.1/npiet -q echo.piet.png
foobar
</code></pre>
<p>You can also see <a href="http://github.com/mame/piet-misc/blob/master/hello.piet.png">hello.piet.png</a> which is translated from <a href="http://en.wikipedia.org/wiki/Brainfuck#Hello_World.21">brainfuck's Hello world!</a></p>
<pre><code>$ ../npiet-1.1/npiet hello.piet.png
Hello, world!
</code></pre>
<p>And now, we can obtain brainfuck interpreter written in Piet, by translating <a href="http://www.bf-hacks.org/hacks/kbfi.b">Keymaker's brainfuck interpreter</a> written in brainfuck!</p>
<pre><code>$ ruby19 bf2piet.rb -c 1 kbfi.b > kbfi.piet.png
$ time ../npiet-1.1/npiet -q kbfi.b < hello.bf
Hello, world!
real 2m35.729s
user 2m35.342s
sys 0m0.128s
</code></pre>
<h3>conclusion</h3>
<p>Given a stack of unlimited size, Piet is Turing-complete. It does not require the stack holding arbitrarily long number.</p>
<p>translated from <a href="http://d.hatena.ne.jp/ku-ma-me/20090925/p1">mamememo in Japanese (2009-09-25)</a>.</p>
<!--[markdown]
I proved Turing-completeness of [the programming language Piet][Piet] by defining a translation from brainfuck to Piet.
### translation approach
#### 1. Correspond brainfuck's tape and piet's stack.
- The top of the piet's stack must equal to the value that the brainfuck's pointer indicates.
- The second top must equal to current index of pointer, plus 3.
- The third top must equal to total length of the whole tape, plus 3.
- The remain part of the stack must equal to data of type except the value on the current pointer.
For example, the following brainfuck's tape:
+---+---+---+---+---+---+
| A | B | C | D | E | F |
+---+---+---+---+---+---+
^
pointer
corresponds to the following piet's stack:
(top) D 6 9 A B C E F (bottom)
where 6 is current index of pointer + 3
9 is total length of tape + 3
#### 2. Define auxiliary functions.
pick(n): push the n-th top value of the stack.
(top) A B C D E F (bottom)
|
| pick(3)
v
(top) D A B C D E F (bottom)
deposit: insert the top value to the n-th index
(top) D 6 9 A B C E F (bottom)
|
| deposit
v
(top) 6 9 A B C D E F (bottom)
withdraw: pull the n-th value to the top (inversion of deposit)
(top) 5 9 A B C D E F (bottom)
|
| withdraw
v
(top) C 5 9 A B D E F (bottom)
definitions:
pick(0) = dup
pick(n) = push(n+1); push(-1); roll; dup; push(n+2); push(1); roll
deposit: pick(1); push(1); roll
withdraw: dup; push(-1); roll
#### 3. Put initializer of the piet's stack.
initial state of the stack:
(top) 0 3 3 (bottom)
#### 4. Put piet's instractions correspoinding to each brainfuck's instruction.
+: push(1); add
-: push(1); sub
>: deposit
if (the second top value) > (top value)
# extend tape
# (top) 9 9 A B C D E F (bottom)
# |
# | extend
# v
# (top) 0 10 10 A B C D E F (bottom)
pop; push(1); add; dup; push(0)
else
push(1); iadd; withdraw
end
<: deposit; push(1); sub; withdraw
[: if (top value) * 2 <= 0
jump the corresponding ']'
end
]: jump the corresponding '['
,: pop; in(char)
.: dup; out(char)
Of course, branches and jumps are represented by "greater", "switch" and "pointer".
Note that the piet's stack is not required to hold arbitrarily long number.
#### 5. Put a terminator of execution.
See [Piet Speficication][Piet].
### full implementation
[http://github.com/mame/piet-misc/blob/master/bf2piet.rb][bf2piet]
### example
An echo program written in brainfuck
,[.,]
is translated to the following Piet program:
$ ruby19 bf2piet.rb echo.bf > echo.piet.png
![echo.piet.png][echo.piet]
You can see ',', '[', '.', ',' and ']' above each corresponding sequence of instructions.
$ echo foobar | ../npiet-1.1/npiet -q echo.piet.png
foobar
You can also see [hello.piet.png][hello.piet] which is translated from [brainfuck's Hello world!][hello.bf]
$ ../npiet-1.1/npiet hello.piet.png
Hello, world!
And now, we can obtain brainfuck interpreter written in Piet, by translating [Keymaker's brainfuck interpreter][kbfi] written in brainfuck!
$ ruby19 bf2piet.rb -c 1 kbfi.b > kbfi.piet.png
$ time ../npiet-1.1/npiet -q kbfi.b < hello.bf
Hello, world!
real 2m35.729s
user 2m35.342s
sys 0m0.128s
### conclusion
Given a stack of unlimited size, Piet is Turing-complete. It does not require the stack holding arbitrarily long number.
translated from [mamememo in Japanese (2009-09-25)](http://d.hatena.ne.jp/ku-ma-me/20090925/p1).
[Piet]: http://www.dangermouse.net/esoteric/piet.html
[bf2piet]: http://github.com/mame/piet-misc/blob/master/bf2piet.rb
[echo.piet]: http://dame.dyndns.org/misc/piet/echo.piet.png
[hello.piet]: http://github.com/mame/piet-misc/blob/master/hello.piet.png
[hello.bf]: http://en.wikipedia.org/wiki/Brainfuck#Hello_World.21
[kbfi]: http://www.bf-hacks.org/hacks/kbfi.b
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com0tag:blogger.com,1999:blog-6309946718175890735.post-68779317051641705442009-10-04T00:59:00.005+09:002009-10-06T00:35:24.953+09:00English blog<p>I write a blog in English. Main contents will be translations from some favorite entries of <a href="http://d.hatena.ne.jp/ku-ma-me/">mamememo in Japanese</a>.</p>
<p>One of the purpose of this blog is English practice. So, please point my Engrish! :-)</p>
<!--[markdown]
I write a blog in English. Main contents will be translations from some favorite entries of [mamememo in Japanese][hatena].
One of the purpose of this blog is English practice. So, please point my Engrish! :-)
[hatena]: http://d.hatena.ne.jp/ku-ma-me/
-->Yusuke Endohhttp://www.blogger.com/profile/10746868996593093045noreply@blogger.com0