怖話.jpをHerokuからさくらVPS 512に移行したのでパフォーマンスを測ってみました。(怖話.jpのアプリに大きく依存しています。また日本向けのサービスなので手元から計測したためネットワーク的にHerokuは不利です。)

  • Heroku
    • kowabana.jp
  • さくら
    • oulu.fjord.jp

さくらVPSではnginx + unicorn + mysqlを使っています。

Apache Bench

% ab -n 1000 -c 100 http://kowabana.jp/
Requests per second:    6.12 [#/sec] (mean)
Time per request:       163.526 [ms] (mean, across all concurrent requests)
% ab -n 1000 -c 100 http://oulu.fjord.jp/
Requests per second:    38.29 [#/sec] (mean)
Time per request:       26.114 [ms] (mean, across all concurrent requests)

Chrome Developer ToolsでのDOMContent event fired

トップページをスーパーリロードした場合。

  • Heroku
    • 1.69s
  • さくら
    • 540ms

結果

人気サイトじゃないのでabの結果はそれほど気にしてませんが、DOMContent event firedはパラパラと残りのパーツが表示されるのは別として、ユーザーにとって「ページが表示された」と感じる実際の時間に近いと思います。それが3倍違うというのは結構な違いだなと思います。確かに体感速度でも速くなったように思います。

怖話.jpをHerokuからさくらVPS 512に移行することにしました。理由は下記です。

  • DB容量が無料の範囲を大幅に超えている。(一応容量オーバーしていても使える)
  • slug(リポジトリ)のサイズが制限(100MB)を超えた。(これはオーバーしているとpushできない)
  • ファイルアップロードが必要になった。(S3を使えば対応は可能)
  • 回線が遅い。(us westとかなので仕方が無い)

Amazon EC2にしなかった理由はまだ人気が無いのでお金をかけられないからです。もし売上が月数十万になったら移行します。

DB移行

HerokuのDBはPostgreSQLです。さくらVPS 512ではMySQLを使うことにしました。

現在のDB容量は37.4MB。レコード数は約2万件ぐらいです。heroku db:pullをしたら1時間たっても終わる気配がなかったので次の方法を取ることにしました。

  • herokuからローカルにpg_dumpを持ってくる。
  • ローカルのpostgresにpg_restore。
  • ローカルのmysqlにtapsサーバーを立てる。
  • ローカルのpostgresからtapsサーバーへpush。
  • ローカルのmysqlからmysqldump。
  • さくらVPSのmysqlにrestore。

大したデータ量じゃないのに、要はネット経由でtapsするととてつもなく時間がかかるのです。

「これ絶対もっと楽な方法あるよなあ」

などと思いながら作業しました。

怖話.jpのランキングの実装を考える。(ニコニコ動画で言えば総合ランキング)

下記の様に各怖い話のスコアを算出してそれでソートする。

スコア = PV数 + 怖いの数 * 1000 + コメント数 * 100

("怖いの数"というのはニコニコ動画で言えば"マイリスト数")

当分の間、特殊なランキングアルゴリズムは必要無いだろう。1000と100という重みは定数にして様子を見ながら変えていく。

人気サイトであれば裏で集計すべきだけどまだ貧弱サイトなので毎回サブクエリで集計してしまおう。

select * from stories order by view + (select count(*) from scares where scares.story_id = stories.id) * 1000 + (select count(*) from comments where comments.story_id = stories.id) * 100 desc, id desc;

我ながらとっても遅そうなクエリだ。

class Story < ActiveRecord::Base
  scope :order_by_ranking, order("view + (select count(*) from scares where scares.story_id = stories.id) * #{Scare::RANKING_WEIGHT} + (select count(*) from comments where comments.story_id = stories.id) * #{Comment::RANKING_WEIGHT} desc, stories.id desc")
end
Story.order_by_ranking.page(params[:page]).per(50)

ActiveRecordとkaminariのお陰でスマートな見た目にできたが、気をつけて実行しなければならない重いsocpeになってしまった。

% heroku plugins:install git://github.com/ddollar/heroku-sql-console.git
% heroku sql
SQL> select * from unk;

It's not psql. It's only send sql and return results.

Title is all. (via @milk1000cc)

Using Capistrano with rvm and bundler.

rvm

# config/deploy.rb:
$:.unshift(File.expand_path('./lib', ENV['rvm_path']))

require 'rvm/capistrano'

set :rvm_ruby_string, 'ruby-1.8.7-p352@kowabana' # Add gemset name if you want to use gemset.
set :rvm_type, :user # If rvm didn't installed to system wides.

bundler

# config/deploy.rb:
require 'bundler/capistrano'

It's all. When run cap deploy:update, Capistrano install gem in shared/bundle.

$ apt-cache search git-core
git-core - fast, scalable, distributed revision control system (obsolete)
git - fast, scalable, distributed revision control system

へー。Debian Squeezeではgit-coreはgitかー。

Lokkathon #3 : ATND

LokkathonはLokka + Hack + Marathonです。 Lokkaに関する作業をモクモクとするイベントです。会場は用意されますが、Lingrのチャットのみでの参加も可能です。(むしろ推奨)

もう明日ですが、Lokkathon #3をやりたいと思います。毎週水曜日のこの時間にやってく予定です。リモート参加前提で、一応場所もあるよという感じです。というか毎週3時間はLokkaの作業をする!という自分に対する縛りです・・・。

単にLokka使ってみたいけどよくわかんないので教えて欲しいとかでも全然OKです。

デザイナーにオススメのMacでのRubyの簡単な設定方法。(何故MacのGEM_HOMEはユーザー別のが先に無いのか - komagata

Snow Leopard, bashというデフォルト状態から、GEM_HOMEを設定するだけ。

~/.bash_profileというファイルに下記を書いてターミナルを再起動してください。

export GEM_HOME=~/.gem/ruby/1.8

これでsudoとかrvmとか無しで好きなrubygemが使えます。railsとかsinatraも使えるよ。

$ gem install sinatra

よくわからなくなってしまったら~/.gemフォルダを削除すれば無かったことにできます。

Let's enjoy ruby and rubygems!

ClojureでJavascriptが書けるClojureScriptが発表されました。(via Clojure/core — Introducing ClojureScript)

と思いかけましたが要はCoffeeScriptと同じアプローチで、

「オブジェクト指向なCoffeeScriptの代わりに関数型言語のClojure(ClojureScript)でJavascript書けるよ」

ということのようです。

とはいえClojureScriptはClojureの完全なJS実装というわけじゃなくて、JVMやJavaコアライブラリに依存してるところも多いので、Pure Clojureなら大体動く予定という感じのようです。

JavascriptとなるとGoogle Closureと名前が紛らわしいわ!という問題は承知してるそうですが、ClojureScript自体がGoogle Closure(Library, Compiler)に依存してるのでややこしいです。

インストール

% git clone git://github.com/clojure/clojurescript.git
% cd clojurescript
% script/bootstrap

ClojureScriptはClojureとJavascriptで書かれてるのでJava 6が必要です。(JavascriptにはRhinoがある)

REPL

% script/repljs
#'user/jse
"Type: " :cljs/quit " to quit"
ClojureScript:cljs.user> (println "foo")
foo
nil

Javascriptへのコンパイル

;; hello.cljs
(ns hello)
(defn ^:export greet [n]
  (str "Hello " n))
% bin/cljsc hello.cljs '{:optimizations :advanced}' > hello.js
;; hello.js
function b(c){throw c;}var f=null;function aa(){return function(c){return c}}function i(c){return function(){return this[c]}}function j(c){return function(){return c}}var k;
function n(c){var a=typeof c;if(a=="object")if(c){if(c instanceof Array)return"array";else if(c instanceof Object)return a;var d=Object.prototype.toString.call(c);if(d=="[object Window]")return"object";if(d=="[object Array]"||typeof c.length=="number"&&typeof c.splice!="undefined"&&typeof c.propertyIsEnumerable!="undefined"&&!c.propertyIsEnumerable("splice"))return"array";if(d=="[object Function]"||typeof c.call!="undefined"&&typeof c.propertyIsEnumerable!="undefined"&&!c.propertyIsEnumerable("call"))return"function"}else return"null";
else if(a=="function"&&typeof c.call=="undefined")return"object";return a}function ba(c){return typeof c=="string"}Math.floor(Math.random()*2147483648).toString(36);var ca={"\000":"\\0","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\x0B",'"':'\\"',"\\":"\\\\"},da={"'":"\\'"};
function ea(c){var m;c=String(c);if(c.quote)return c.quote();else{for(var a=['"'],d=0;d31&&g<127))if(e in da)e=da[e];else if(e in ca)m=da[e]=ca[e],e=m;else{g=e;o=e.charCodeAt(0);if(o>31&&o<127)g=e;else{if(o<256){if(g="\\x",o<16||o>256)g+="0"}else g="\\u",o<4096&&(g+="0");g+=o.toString(16).toUpperCase()}e=da[e]=g}o=e}h[l]=o}a.push('"');return a.join("")}}
function fa(c){for(var a=0,d=0;de;default:return c.apply(this,
arguments)}b("Invalid arity: "+arguments.length)};a.c=2;a.a=function(a){var e=K(a),g=K(M(a)),a=L(M(a));return c.call(f,e,g,a)};return a}();function gb(c){return eb.call(f,c,1)}function hb(c,a){return c^a}function ib(c,a){return c<>a}function kb(c){return O.call(f,0,c)}function lb(c,a){for(var d=a,e=J.call(f,c);;)if(s(function(){var a=e;return s(a)?kb.call(f,d):a}()))var g=gb.call(f,d),h=M.call(f,e),d=g,e=h;else return e}
x._=function(){return function(c,a,d){switch(arguments.length){case 2:var e;var g=lb.call(f,c,a);s(g)?e=K.call(f,g):b("Index out of bounds");return e;case 3:return e=lb.call(f,c,a),s(e)?K.call(f,e):d}b("Invalid arity: "+arguments.length)}}();
var Q=function(){function c(c,e){var g=I(Array.prototype.slice.call(arguments,1),0);return function(c,d){for(;;)if(s(d))var e=c.append(a.call(f,K.call(f,d))),g=M.call(f,d),c=e,d=g;else return a.call(f,c)}.call(f,new r(a.call(f,c)),g)}var a=f,a=function(a,e){switch(arguments.length){case 0:return"";case 1:return s(C.call(f,a))?"":a.toString();default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};a.c=1;a.a=function(a){var e=K(a),a=L(a);return c.call(f,e,a)};return a}(),mb=function(){return function(c,
a,d){switch(arguments.length){case 2:return c.substring(a);case 3:return c.substring(a,d)}b("Invalid arity: "+arguments.length)}}();function H(c,a){return Za.call(f,s(Ua.call(f,a))?function(){for(var d=J.call(f,c),e=J.call(f,a);;)if(s(C.call(f,d)))return C.call(f,e);else if(s(C.call(f,e)))return!1;else if(s(B.call(f,K.call(f,d),K.call(f,e))))d=M.call(f,d),e=M.call(f,e);else return s("\ufdd0'else")?!1:f}():f)}
function nb(c,a){return hb.call(f,c,db.call(f,a,2654435769,ib.call(f,c,6),jb.call(f,c,2)))}function R(c){return N.call(f,function(a,c){return nb.call(f,a,Ta.call(f,c))},Ta.call(f,K.call(f,c)),M.call(f,c))}function ob(c,a,d,e){this.b=c;this.C=a;this.z=d;this.count=e}k=ob.prototype;k.f=function(c,a){return H.call(f,c,a)};k.i=function(c,a){return new ob(this.b,a,c,E.call(f,this.count))};k.o=i("C");k.p=i("z");k.h=aa();k.m=!0;k.n=i("b");k.j=function(c){return R.call(f,c)};k.t=i("count");k.q=!0;
function pb(c){this.b=c}k=pb.prototype;k.f=function(c,a){return H.call(f,c,a)};k.i=function(c,a){return new ob(this.b,a,f,1)};k.o=j(f);k.p=j(f);k.h=j(f);k.m=!0;k.n=i("b");k.j=function(c){return R.call(f,c)};k.t=j(0);k.q=!0;var qb=new pb(f);function rb(c){return N.call(f,Oa,qb,c)}function D(c){var a=I(Array.prototype.slice.call(arguments,0),0);return N.call(f,Oa,qb,rb.call(f,a))}function sb(c,a,d){this.b=c;this.C=a;this.z=d}k=sb.prototype;k.h=aa();k.j=function(c){return R.call(f,c)};
k.f=function(c,a){return H.call(f,c,a)};k.q=!0;k.i=function(c,a){return new sb(f,a,c)};k.o=i("C");k.p=function(){return s(C.call(f,this.z))?qb:this.z};k.m=!0;k.n=i("b");function S(c,a){return new sb(f,c,a)}z.string=function(){return function(c,a,d){switch(arguments.length){case 2:return G.call(f,c,a);case 3:return G.call(f,c,a,d)}b("Invalid arity: "+arguments.length)}}();
y.string=function(){return function(c,a,d){switch(arguments.length){case 2:return x.call(f,c,a);case 3:return x.call(f,c,a,d)}b("Invalid arity: "+arguments.length)}}();x.string=function(){return function(c,a,d){switch(arguments.length){case 2:return s(O.call(f,a,w.call(f,c)))?c.charAt(a):f;case 3:return s(O.call(f,a,w.call(f,c)))?c.charAt(a):d}b("Invalid arity: "+arguments.length)}}();w.string=function(c){return c.length};Ca.string=function(c){return Ka.call(f,c,0)};
Aa.string=function(c){return fa.call(f,c)};this.String.prototype.call=function(){return function(c,a,d){switch(arguments.length){case 2:return Qa.call(f,a,this.toString());case 3:return Qa.call(f,a,this.toString(),d)}b("Invalid arity: "+arguments.length)}}();function tb(c){var a=c.x;return s(c.D)?a:(c.x=a.call(f),c.D=!0,c.x)}function T(c,a,d){this.b=c;this.D=a;this.x=d}k=T.prototype;k.h=function(c){return J.call(f,tb.call(f,c))};k.j=function(c){return R.call(f,c)};
k.f=function(c,a){return H.call(f,c,a)};k.q=!0;k.i=function(c,a){return S.call(f,a,c)};k.o=function(c){return K.call(f,tb.call(f,c))};k.p=function(c){return L.call(f,tb.call(f,c))};k.m=!0;k.n=i("b");function U(c){for(var a=v.call(f);;)if(s(J.call(f,c)))a.push(K.call(f,c)),c=M.call(f,c);else return a}function ub(c,a){for(var d=c,e=a,g=0;;)if(s(function(){var a=kb.call(f,e);return s(a)?J.call(f,d):a}()))var h=M.call(f,d),l=gb.call(f,e),g=E.call(f,g),d=h,e=l;else return g}
var wb=function vb(a){return s(C.call(f,a))?f:s(C.call(f,M.call(f,a)))?J.call(f,K.call(f,a)):s("\ufdd0'else")?S.call(f,K.call(f,a),vb.call(f,M.call(f,a))):f},xb=function(){function c(a,c,d){var e=I(Array.prototype.slice.call(arguments,2),0);return function t(a,c){return new T(f,!1,function(){var d=J.call(f,a);return s(d)?S.call(f,K.call(f,d),t.call(f,L.call(f,d),c)):s(c)?t.call(f,K.call(f,c),M.call(f,c)):f})}.call(f,g.call(f,a,c),e)}function a(a,c){return new T(f,!1,function(){var d=J.call(f,a);return s(d)?
S.call(f,K.call(f,d),g.call(f,L.call(f,d),c)):c})}function d(a){return new T(f,!1,function(){return a})}function e(){return new T(f,!1,j(f))}var g=f,g=function(g,l,o){switch(arguments.length){case 0:return e.call(this);case 1:return d.call(this,g);case 2:return a.call(this,g,l);default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};g.c=2;g.a=function(a){var d=K(a),e=K(M(a)),a=L(M(a));return c.call(f,d,e,a)};return g}(),yb=function(){function c(a,c,g,h,l){var o=I(Array.prototype.slice.call(arguments,
4),0);return S.call(f,a,S.call(f,c,S.call(f,g,S.call(f,h,wb.call(f,o)))))}var a=f,a=function(a,e,g,h,l){switch(arguments.length){case 1:return J.call(f,a);case 2:return S.call(f,a,e);case 3:return S.call(f,a,S.call(f,e,g));case 4:return S.call(f,a,S.call(f,e,S.call(f,g,h)));default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};a.c=4;a.a=function(a){var e=K(a),g=K(M(a)),h=K(M(M(a))),l=K(M(M(M(a)))),a=L(M(M(M(a))));return c.call(f,e,g,h,l,a)};return a}(),zb=function(){function c(a,
c,g,h,l,o){var m=I(Array.prototype.slice.call(arguments,5),0),m=S.call(f,c,S.call(f,g,S.call(f,h,S.call(f,l,wb.call(f,m))))),p=a.c;return s(a.a)?s(P.call(f,ub.call(f,m,p),p))?a.apply(a,U.call(f,m)):a.a(m):a.apply(a,U.call(f,m))}var a=f,a=function(a,e,g,h,l,o){switch(arguments.length){case 2:var m=a,p=e,t=m.c;return s(m.a)?s(P.call(f,ub.call(f,p,t),t))?m.apply(m,U.call(f,p)):m.a(p):m.apply(m,U.call(f,p));case 3:return m=a,p=yb.call(f,e,g),t=m.c,s(m.a)?s(P.call(f,ub.call(f,p,t),t))?m.apply(m,U.call(f,
p)):m.a(p):m.apply(m,U.call(f,p));case 4:return m=a,p=yb.call(f,e,g,h),t=m.c,s(m.a)?s(P.call(f,ub.call(f,p,t),t))?m.apply(m,U.call(f,p)):m.a(p):m.apply(m,U.call(f,p));case 5:return m=a,p=yb.call(f,e,g,h,l),t=m.c,s(m.a)?s(P.call(f,ub.call(f,p,t),t))?m.apply(m,U.call(f,p)):m.a(p):m.apply(m,U.call(f,p));default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};a.c=5;a.a=function(a){var e=K(a),g=K(M(a)),h=K(M(M(a))),l=K(M(M(M(a)))),o=K(M(M(M(M(a))))),a=L(M(M(M(M(a)))));return c.call(f,
e,g,h,l,o,a)};return a}();function Ab(c,a){for(;;)if(s(C.call(f,J.call(f,a))))return!0;else if(s(c.call(f,K.call(f,a))))var d=c,e=M.call(f,a),c=d,a=e;else return s("\ufdd0'else")?!1:f}function Bb(c){return c}
var V=function(){function c(a,c,d,e,p){var t=I(Array.prototype.slice.call(arguments,4),0);return g.call(f,function(c){return zb.call(f,a,c)},function Nb(a){return new T(f,!1,function(){var c=g.call(f,J,a);return s(Ab.call(f,Bb,c))?S.call(f,g.call(f,K,c),Nb.call(f,g.call(f,L,c))):f})}.call(f,Oa.call(f,t,e,d,c)))}function a(a,c,d,e){return new T(f,!1,function(){var p=J.call(f,c),t=J.call(f,d),Ia=J.call(f,e);return s(s(p)?s(t)?Ia:t:p)?S.call(f,a.call(f,K.call(f,p),K.call(f,t),K.call(f,Ia)),g.call(f,
a,L.call(f,p),L.call(f,t),L.call(f,Ia))):f})}function d(a,c,d){return new T(f,!1,function(){var e=J.call(f,c),p=J.call(f,d);return s(s(e)?p:e)?S.call(f,a.call(f,K.call(f,e),K.call(f,p)),g.call(f,a,L.call(f,e),L.call(f,p))):f})}function e(a,c){return new T(f,!1,function(){var d=J.call(f,c);return s(d)?S.call(f,a.call(f,K.call(f,d)),g.call(f,a,L.call(f,d))):f})}var g=f,g=function(g,l,o,m,p){switch(arguments.length){case 2:return e.call(this,g,l);case 3:return d.call(this,g,l,o);case 4:return a.call(this,
g,l,o,m);default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};g.c=4;g.a=function(a){var d=K(a),e=K(M(a)),g=K(M(M(a))),p=K(M(M(M(a)))),a=L(M(M(M(a))));return c.call(f,d,e,g,p,a)};return g}(),Db=function Cb(a,d){return new T(f,!1,function(){if(s(kb.call(f,a))){var e=J.call(f,d);return s(e)?S.call(f,K.call(f,e),Cb.call(f,gb.call(f,a),L.call(f,e))):f}else return f})};
function Eb(c,a){function d(a,c){for(;;){var d=J.call(f,c);if(s(function(){var c=kb.call(f,a);return s(c)?d:c}()))var l=gb.call(f,a),o=L.call(f,d),a=l,c=o;else return d}}return new T(f,!1,function(){return d.call(f,c,a)})}
var Fb=function(){function c(c){return new T(f,!1,function(){return S.call(f,c,a.call(f,c))})}var a=f;return a=function(d,e){switch(arguments.length){case 1:return c.call(this,d);case 2:return Db.call(f,d,a.call(f,e))}b("Invalid arity: "+arguments.length)}}(),Gb=function(){function c(a,c,h){var l=I(Array.prototype.slice.call(arguments,2),0);return new T(f,!1,function(){var h=V.call(f,J,Oa.call(f,l,c,a));return s(Ab.call(f,Bb,h))?xb.call(f,V.call(f,K,h),zb.call(f,d,V.call(f,L,h))):f})}function a(a,
c){return new T(f,!1,function(){var h=J.call(f,a),l=J.call(f,c);return s(s(h)?l:h)?S.call(f,K.call(f,h),S.call(f,K.call(f,l),d.call(f,L.call(f,h),L.call(f,l)))):f})}var d=f,d=function(d,g,h){switch(arguments.length){case 2:return a.call(this,d,g);default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};d.c=2;d.a=function(a){var d=K(a),h=K(M(a)),a=L(M(a));return c.call(f,d,h,a)};return d}();function Hb(c,a){return Eb.call(f,1,Gb.call(f,Fb.call(f,c),a))}
function Ib(c){return function d(c,g){return new T(f,!1,function(){var h=J.call(f,c);return s(h)?S.call(f,K.call(f,h),d.call(f,L.call(f,h),g)):s(J.call(f,g))?d.call(f,K.call(f,g),L.call(f,g)):f})}.call(f,f,c)}
var Jb=function(){function c(a,c,g){var h=I(Array.prototype.slice.call(arguments,2),0);return Ib.call(f,zb.call(f,V,a,c,h))}var a=f,a=function(a,e,g){switch(arguments.length){case 2:return Ib.call(f,V.call(f,a,e));default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};a.c=2;a.a=function(a){var e=K(a),g=K(M(a)),a=L(M(a));return c.call(f,e,g,a)};return a}(),Kb=function(){function c(a,c,h,l){return new T(f,!1,function(){var o=J.call(f,l);if(s(o)){var m=Db.call(f,a,o);return s(B.call(f,
a,Pa.call(f,m)))?S.call(f,m,d.call(f,a,c,h,Eb.call(f,c,o))):D.call(f,Db.call(f,a,xb.call(f,m,h)))}else return f})}function a(a,c,h){return new T(f,!1,function(){var l=J.call(f,h);if(s(l)){var o=Db.call(f,a,l);return s(B.call(f,a,Pa.call(f,o)))?S.call(f,o,d.call(f,a,c,Eb.call(f,c,l))):f}else return f})}var d=f;return d=function(e,g,h,l){switch(arguments.length){case 2:return d.call(f,e,e,g);case 3:return a.call(this,e,g,h);case 4:return c.call(this,e,g,h,l)}b("Invalid arity: "+arguments.length)}}();
function W(c,a){this.b=c;this.d=a}k=W.prototype;k.f=function(c,a){return H.call(f,c,a)};k.i=function(c,a){var d=ia.call(f,this.d);d.push(a);return new W(this.b,d)};k.h=function(){var c=this;return s(fb.call(f,c.d.length,0))?function d(e){return new T(f,!1,function(){return s(O.call(f,e,c.d.length))?S.call(f,c.d[e],d.call(f,E.call(f,e))):f})}.call(f,0):f};k.G=!0;
k.w=function(){function c(a,c,g){var h=this;return s(function(){var a=P.call(f,0,c);return s(a)?O.call(f,c,h.d.length):a}())?h.d[c]:g}function a(a,c){var g=this;return s(function(){var a=P.call(f,0,c);return s(a)?O.call(f,c,g.d.length):a}())?g.d[c]:f}return function(d,e,g){switch(arguments.length){case 2:return a.call(this,0,e);case 3:return c.call(this,0,e,g)}b("Invalid arity: "+arguments.length)}}();k.m=!0;k.n=i("b");
k.v=function(){return function(c,a,d){switch(arguments.length){case 2:return G.call(f,this.d,a);case 3:return G.call(f,this.d,a,d)}b("Invalid arity: "+arguments.length)}}();k.j=function(c){return R.call(f,c)};k.t=function(){return this.d.length};k.q=!0;k.B=function(c,a,d){c=ia.call(f,this.d);c[a]=d;return new W(this.b,c)};k.u=function(){return function(c,a,d){switch(arguments.length){case 2:return x.call(f,c,a,f);case 3:return x.call(f,c,a,d)}b("Invalid arity: "+arguments.length)}}();
var Lb=new W(f,v.call(f));function Mb(c){return new W(f,c)}W.prototype.call=function(){return function(c,a,d){switch(arguments.length){case 2:return y.call(f,this,a);case 3:return y.call(f,this,a,d)}b("Invalid arity: "+arguments.length)}}();function Ob(c){return N.call(f,Oa,Lb,c)}function Pb(){}Pb.prototype.f=j(!1);var Qb=new Pb;
function Rb(c,a){return Za.call(f,s(Va.call(f,a))?s(B.call(f,Pa.call(f,c),Pa.call(f,a)))?Ab.call(f,Bb,V.call(f,function(c){return B.call(f,Qa.call(f,a,K.call(f,c),Qb),La.call(f,c))},c)):f:f)}function Sb(c,a,d){for(var e=d.length,g=0;;)if(s(O.call(f,g,e)))if(s(B.call(f,a,d[g])))return g;else g=db.call(f,g,c);else return f}v.call(f);function X(c,a,d){this.b=c;this.count=a;this.r=d}k=X.prototype;k.f=function(c,a){return Rb.call(f,c,a)};
k.i=function(c,a){return s(Wa.call(f,a))?ra.call(f,c,x.call(f,a,0),x.call(f,a,1)):N.call(f,la,c,a)};k.h=function(){var c=this;if(s(kb.call(f,c.count))){var a=Xa.call(f,c.r);return Jb.call(f,function(a){return V.call(f,Ob,Kb.call(f,2,c.r[a]))},a)}else return f};k.F=!0;k.m=!0;k.n=i("b");k.j=function(c){return R.call(f,c)};k.t=i("count");
k.B=function(c,a,d){var c=Ta.call(f,a),e=this.r[c];if(s(e)){var e=ia.call(f,e),g=ha.call(f,this.r);g[c]=e;c=Sb.call(f,2,a,e);return s(c)?(e[E.call(f,c)]=d,new X(this.b,this.count,g)):(e.push(a,d),new X(this.b,E.call(f,this.count),g))}else return e=ha.call(f,this.r),e[c]=v.call(f,a,d),new X(this.b,E.call(f,this.count),e)};
k.u=function(){return function(c,a,d){switch(arguments.length){case 2:return y.call(f,c,a,f);case 3:var e=this.r[Ta.call(f,a)],g=s(e)?Sb.call(f,2,a,e):f;return s(g)?e[E.call(f,g)]:d}b("Invalid arity: "+arguments.length)}}();var Tb=new X(f,0,function(){return{}}.call(f));X.prototype.call=function(){return function(c,a,d){switch(arguments.length){case 2:return y.call(f,this,a);case 3:return y.call(f,this,a,d)}b("Invalid arity: "+arguments.length)}}();
function Ha(c){for(var a=I(Array.prototype.slice.call(arguments,0),0),a=J.call(f,a),d=Tb;;)if(s(a))var e=Ma.call(f,a),d=Ra.call(f,d,K.call(f,a),La.call(f,a)),a=e;else return d}Ha.call(f);function Ub(c){if(s($a.call(f,c)))return c;else if(s(function(){var a=ab.call(f,c);return s(a)?a:bb.call(f,c)}())){var a=c.lastIndexOf("/");return s(O.call(f,a,0))?mb.call(f,c,2):mb.call(f,c,E.call(f,a))}else return f}
function Vb(c){if(s(function(){var a=ab.call(f,c);return s(a)?a:bb.call(f,c)}())){var a=c.lastIndexOf("/");return s(fb.call(f,a,-1))?mb.call(f,c,2,a):f}else return"\ufdd0'else"}function Y(c,a,d,e,g,h){return xb.call(f,Mb([a]),Ib.call(f,Hb.call(f,Mb([d]),V.call(f,function(a){return c.call(f,a,g)},h))),Mb([e]))}
var Z=function Wb(a,d){return s(C.call(f,a))?D.call(f,"nil"):s(Ya.call(f,a))?D.call(f,"#"):s("\ufdd0'else")?xb.call(f,s(function(){var e=Qa.call(f,d,"\ufdd0'meta");return s(e)?(e=s(s(a)?a.m:a)?!0:u.call(f,ua,a),s(e)?Sa.call(f,a):e):e}())?xb.call(f,Mb(["^"]),Wb.call(f,Sa.call(f,a),d),Mb([" "])):f,s(s(s(a)?a.k:a)?!0:u.call(f,A,a))?Fa.call(f,a,d):D.call(f,"#<",Q.call(f,a),">")):f};X.prototype.k=!0;
X.prototype.g=function(c,a){return Y.call(f,function(c){return Y.call(f,Z,""," ","",a,c)},"{",", ","}",a,c)};A.number=!0;Fa.number=function(c){return D.call(f,Q.call(f,c))};Ja.prototype.k=!0;Ja.prototype.g=function(c,a){return Y.call(f,Z,"("," ",")",a,c)};T.prototype.k=!0;T.prototype.g=function(c,a){return Y.call(f,Z,"("," ",")",a,c)};A["boolean"]=!0;Fa["boolean"]=function(c){return D.call(f,Q.call(f,c))};A.string=!0;
Fa.string=function(c,a){return s(ab.call(f,c))?D.call(f,Q.call(f,":",function(){var a=Vb.call(f,c);return s(a)?Q.call(f,a,"/"):f}(),Ub.call(f,c))):s(bb.call(f,c))?D.call(f,Q.call(f,function(){var a=Vb.call(f,c);return s(a)?Q.call(f,a,"/"):f}(),Ub.call(f,c))):s("\ufdd0'else")?D.call(f,s("\ufdd0'readably".call(f,a))?ea.call(f,c):c):f};W.prototype.k=!0;W.prototype.g=function(c,a){return Y.call(f,Z,"["," ","]",a,c)};ob.prototype.k=!0;ob.prototype.g=function(c,a){return Y.call(f,Z,"("," ",")",a,c)};
A.array=!0;Fa.array=function(c,a){return Y.call(f,Z,"#",a,c)};pb.prototype.k=!0;pb.prototype.g=function(){return D.call(f,"()")};sb.prototype.k=!0;sb.prototype.g=function(c,a){return Y.call(f,Z,"("," ",")",a,c)};function Xb(c){return Q.call(f,"Hello ",c)}var Yb="hello.greet".split("."),$=this;!(Yb[0]in $)&&$.execScript&&$.execScript("var "+Yb[0]);for(var Zb;Yb.length&&(Zb=Yb.shift());)!Yb.length&&Xb!==void 0?$[Zb]=Xb:$=$[Zb]?$[Zb]:$[Zb]={};

Webでの実行

<html>
  <head></head>
  <body>
    <script type="text/javascript" src="hello.js"></script>
    <script>
      alert(hello.greet("ClojureScript"))
    </script>
  </body>
</html>

感想

お、動くじゃん。

ただ、CoffeeScriptの利点は吐かれるJSもかなり可読性が高いものになる(それこそ俺が適当に手書きしたJSより)というところだと思うので、元々関数型で結構書きやすいJSを関数型言語からイミフなJSにコンパイルするのはちょっとなーという感じです。モジュール性を高めたい場合にはunderscore.js等を使ってJSネイティブで関数型っぽく書く方が僕は惹かれています。

ClojureScriptをnodejsで動かすって部分は更にイミフです。サーバーサイドだったらClojureそのもので書いたらえんちゃうの?

JavascriptはWebのアセンブラだ!っていう考えは今後主流になったりするんでしょうかね。どうなんでしょうかね。