Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

2017-04-27

KaTeXを使ってみた感想

ブラウザー上で動いて、texの数式を描画するライブラリには、有名なMathJaxの他に、KaTeXがある。

Khan/KaTeX: Fast math typesetting for the web.

KaTeXにはMathJaxにない様々利点があるが、欠点も多い。

マストドンで数式描画をするのにMathJaxの代わりにKaTeXが使えないかと試してみたが、結論から言うと、KaTeXはマストドンで使うのに適さない。

KaTeXは以下の用途で使うのに適している。

  1. 自分一人、あるいは十分に訓練されて連絡を密に取り合う人間だけで編集された文書
  2. 数式に間違いがなく、KaTeXで処理できること

以下のような場合には適さない。

  1. 不特定多数の人間が数式を入力する
  2. 数式は文法的に誤りを含む可能性がる

KaTeXの利点

KaTeXはMathJaxに比較して様々な利点がある。

速い。文句なくMathJaxより速い。

KaTeX and MathJax Comparison Demo

実装が軽量で依存がなくWebサイトに組み込みやすい。

JavaScriptファイル一つ、CSSファイル一つ、あとはフォントファイルしかない。

KaTeXはかなり理想的なのだが、問題がある。

数式のパースエラーに非寛容

数式がtexの文法違反だったりするとすぐに例外を投げる。例外を無効化もできるが、基本的にパースエラーを出した時点でそれ以上の処理を拒否する。

CJK文字に対応していない。

これは本当に耐え難い問題だ。我々は$力=質量\times加速度$を書くときは、

$力=質量\times加速度$

と書きたい。しかし、KaTeXはCJK文字に対応していない。

一応、\text{}で囲めば使えるらしいが、それは式の意味を買えてしまうし、第一、

$\text{力}=\text{質量}\times\text{加速度}$

とは書きたくない。そもそも意味が変わってしまう。不特定多数のユーザーがいる場合にこれを守らせるのも難しい。それにこうしてもやはりCJK文字の扱いには問題がある。

それ以外にも、基本的にエラーを出すと処理を中止するようになっていて、本当に使いづらい。

このため、KaTeXはマストドンで使うのに適さない。

2017-04-26

どんなWebページでもtexによる数式描画を追加できるブラウザー拡張

EzoeRyou/inject-mathjax: どんなWebページにもMathJaxをロードするブラウザー拡張

任意のWebページにMathJaxを読み込ませてtexによる数式表現を化膿するChromium, Google Chrome向けブラウザー拡張。

インストール


git clone
vim whitelist_urls.conf
make

してからChromiumにインストールする。

whitelist_urls.confには一行にひとつ、MathJaxを読み込ませたいURLをマッチパターンで記述する

Match Patterns - Google Chrome

特徴

このブラウザー拡張はwhitelist_url.confに記述したマッチパターンのURLに対し、

  1. CSP(Content Security Policy)を無効化する
  2. MathJaxをロードする
  3. MathJaxを定期的に呼び出す

という処理を行う。

類似のブラウザー拡張より優れている点

すでに類似機能を提供しているブラウザー拡張があるが、コンピューターリテラシーのないユーザーのためにあまり洗練されていない実装になっている。

CSPの普及により、多くのWebサイトでは外部ドメインのスクリプトがロードできなくなっている。CDN経由でMathJaxをロードするには、まずCSPを無効化しなければならない。CSPはセキュリティを向上させるものであり、不必要に無効化すべきではない。そのため、MathJaxをロードする必要があるURLのみ無効化すべきだ。 Chromium, Google ChromeでCSPを無効化するには、レスポンスヘッダーをブラウザーが解釈する前に改変するブラウザー拡張用の機能を使う。そしてCSPの部分を削除する。

これは以下のようなコードになる。


for (var i = 0; i < details.responseHeaders.length; i++) {
    if ('content-security-policy' === details.responseHeaders[i].name.toLowerCase()) {
        details.responseHeaders[i].value = '';
        // 実際にはCDNを追加するのでもう少しマシ
    }
}

巷に出回っているブラウザー拡張は、このレスポンスヘッダーからCSPを削除するためのコールバック関数を、すべてのURLに対して読み出す。そして、自薦に設定したURLのみに適用するように条件分岐する。


function( details ) {

    if ( !is_whiltelist_urls(details.url) )
        return ;
}

ブラウザー拡張側のコードでURLを判定している。

理想的には、ブラウザー拡張のmanifest.jsonのpermissionsで適用されるURLを厳しく指定すべきだ。しかし、そのためにはユーザーがmanifest.jsonを変更する必要がある。

このブラウザー拡張は、whitelist_urls.confに記述されたマッチパターンをpermissionsにもつmanifest.jsonを生成して、ブラウザー拡張をユーザーが作るようになっている。

2017-04-24

マストドンで数式を表示するブックマークレット

読者はすでにマストドンをしているだろうか。マストドンは自由なSNSで未来がある。もはや不自由なSNSであるTwitterやFacebookの時代は終わった。今年中にも滅びるだろう。

さて、マストドンで不便な点として、数式が表示できないという問題がある。しかし、これは自由なソフトウェアであれば改良が可能だ。

以下のリンクをブックマークバーまでドラッグするか、URLをコピーしてブックマークとして追加しよう。

#mathトドン

そして、マストドンを開いたタブで、ブックマークをクリックするのだ。

すると、

$$
 \mathsf{K}_\nu(x) =
  (\pi/2)\mathrm{i}^{\nu+1} (            \mathsf{J}_\nu(\mathrm{i}x)
       + \mathrm{i} \mathsf{N}_\nu(\mathrm{i}x)
       )
  =
  \left\{
  \begin{array}{cl}
  \displaystyle
  \frac{\pi}{2}
  \frac{\mathsf{I}_{-\nu}(x) - \mathsf{I}_{\nu}(x)}
       {\sin \nu\pi },
  & \mbox{for $x \ge 0$ and non-integral $\nu$}
  \\
  \\
  \displaystyle
  \frac{\pi}{2}
  \lim_{\mu \rightarrow \nu} \frac{\mathsf{I}_{-\mu}(x) - \mathsf{I}_{\mu}(x)}
                                  {\sin \mu\pi },
  & \mbox{for $x \ge 0$ and integral $\nu$}
  \end{array}
  \right.$$

$$ \mathsf{K}_\nu(x) = (\pi/2)\mathrm{i}^{\nu+1} ( \mathsf{J}_\nu(\mathrm{i}x) + \mathrm{i} \mathsf{N}_\nu(\mathrm{i}x) ) = \left\{ \begin{array}{cl} \displaystyle \frac{\pi}{2} \frac{\mathsf{I}_{-\nu}(x) - \mathsf{I}_{\nu}(x)} {\sin \nu\pi }, & \mbox{for $x \ge 0$ and non-integral $\nu$} \\ \\ \displaystyle \frac{\pi}{2} \lim_{\mu \rightarrow \nu} \frac{\mathsf{I}_{-\mu}(x) - \mathsf{I}_{\mu}(x)} {\sin \mu\pi }, & \mbox{for $x \ge 0$ and integral $\nu$} \end{array} \right.$$

と表示される。ちなみにこれはIrregular modified cylindrical Bessel functionだ。

これで、マストドンで数式を表現できる。このブックマークレットを使っているもの同士ならば、数式で会話できる。

ちなみに、コードは以下の通り。

(function(){

var config = document.createElement( "script" ) ;
config.type = "text/x-mathjax-config" ;
config.appendChild( document.createTextNode( 'MathJax.Hub.Config({tex2jax: {inlineMath: [["$","$"], ["\\\\(","\\\\)"]]}});' ) ) ;

document.head.appendChild(config) ;

let script = document.createElement( "script" ) ;
script.type = "text/javascript" ;
script.async="async" ;
script.src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_SVG" ;

let inner_script =
    'window.setInterval( function() { MathJax.Hub.Queue(["Typeset",MathJax.Hub]); '
+   'let textarea = document.getElementsByClassName("autosuggest-textarea__textarea")[0] ;'
+   'if ( textarea !== null && textarea.value === "" )'
+       'textarea.value = "#math " ;'
+   '}, 1000 ) ;' ;


script.appendChild( document.createTextNode( inner_script ) ) ;

document.head.appendChild(script) ;
})() ;

ちなみに、このコードはデフォルトで入力欄に#mathを入力する。この挙動が気に入らない人は、以下のブックマークレットを使うとよい。

mathトドン

コードは以下の通り。

(function(){
var config = document.createElement( "script" ) ;
config.type = "text/x-mathjax-config" ;
config.appendChild( document.createTextNode( 'MathJax.Hub.Config({tex2jax: {inlineMath: [["$","$"], ["\\\\(","\\\\)"]]}});' ) ) ;

document.head.appendChild(config) ;

let script = document.createElement( "script" ) ;
script.type = "text/javascript" ;
script.async="async" ;
script.src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_SVG" ;

let inner_script = 'window.setInterval( function() { MathJax.Hub.Queue(["Typeset",MathJax.Hub]); }, 1000 ) ;' ;



script.appendChild( document.createTextNode( inner_script ) ) ;

document.head.appendChild(script) ;
})() ;

2016-08-24

npm、一見無意味なパッケージを消したら1000件ものパッケージが依存するパッケージであったことが判明

npmが一見無意味に思えるfsというパッケージをSPAMとみなして削除したところ、1000件ほどのパッケージが依存するパッケージだったので、削除を取り消した。

npm, Inc. Status - "fs" unpublished and restored

今日、数分ほど、"fs"というパッケージが、ユーザーからSPAMであるという報告を受けて、レジストリから非公開にされた。これは現在復旧されている。これは私(@seldo)による人為的なミスである。私は非公開が安全であるかを確認する内部のガイドラインに従っていなかった。ビルドが阻害されたユーザーに謝罪する。

詳細:"fs"というパッケージは、無意味なパッケージである。これは単に"I am fs"をログに残して終了する。このパッケージが何らかのモジュールの依存に含まれるべき理由は一切ない。しかし、1000件ほどのパッケージが、誤って"fs"に依存している。おそらく、"fs"という組み込みのnodeモジュールを使おうとしているのだろう。この理由により、我々は同モジュールを非公開ではなく、ガイドラインに従って、deprecated扱いにした。

もし、既存のモジュールが"fs"に依存しているのであれば、安全に消すことができる。実際、消すべきである。仮に消さなかったとしても、今後も問題なく動作はする。

npmやnodejsが悪いのか、nodejs界隈のユーザー層が悪いのか判断に苦しむが、いずれにせよnode.jsはクソであることがわかる。

2016-06-21

Chrome 51のV8の興味深いバグ

以下のコードを実行した結果を予想してみてほしい。


function foo()
{
    return typeof null === "undefined" ;
}

for ( var i = 0 ; i < 1000 ; ++i )
{
    console.log( foo() ) ;
}

typeof nullの結果は"object"なので、"undefined"と===で比較するとfalseになる。したがって、関数fooは必ずfalseを返すはずである。1000回実行しようと常にfalseを返す関数は常にfalseを返すはずである。

では実際に実行して確かめてみよう。

コンソールにコピペするのとは挙動が違うが、何度もクリックすると、なぜかtrueを返すようになる。おそらく、コンソールにコピペすると毎回JITが走るので、挙動が違うのだろう。

ちなみに、workaroundとしては、typeof null === undefinedとかtypeof null === "undefined" + ""などがあるらしい。

参考

Javascript developers, be warned about this crazy JIT bug in V8!

Issue 604033 - chromium - JIT compiler not preserving method behavior - Monorail

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-03-24

npmからkikとその他諸々が消されたまとめ

npmとは、node.jsにおけるパッケージシステムのことだ。npmを使えば、他人の書いたnode.jsベースのプログラムとライブラリの入手と利用がとても簡単になる。

そのnpm界隈が混乱している。発端は以下のURLだ。

I’ve Just Liberated My Modules — Medium

Azer Koçuluはkikという名前のnpmパッケージを公開していた。このkikというソフトウェアの中身についてはここでは関係がない。

さて、それとは別に、kik.comというスマフォ用のチャットアプリを出しているKik Interactive社がいて、kikという名前のパッケージをnpmで出したいので、名前を明け渡すように要求した。

Azerはこの要求を拒否した。すると、Kik Interactive社はnpmの管理者に片っ端からメールを投げまくり、そのうちの一人が反応して、Azerの意思に反して、何の法的根拠もなくパッケージを消した。

Azerはこの行動に対し、npmはもはや信頼できないとし、npmに出していたすべてのパッケージを削除した。

そして阿鼻叫喚の世界に突入する。Azerは様々なCLIツールやライブラリをnpmで公開していた。中でも影響力のあったAzerのパッケージは、left-padだ。

azer/left-pad: String left pad

left-padとは、文字列の左側(先頭)を指定した文字数になるように、指定した文字か指定されない場合は空白文字でパディング(埋める)だけの処理を行う簡単なJavaScriptで書かれたleftpadという名前のライブラリだ。空行を抜けば、10行ぐらいしかない簡単なコードだ。

このコードは有名なnpmパッケージで使われていたらしく、間接的に様々なnpmパッケージが依存していたため、世界中で大混乱を引き起こすことになった。

傑作なのは、当のKik Interactive社すらleft-padに依存していたということだ。Kik Interactive社は今回の件について、メールをすべて公開している。

A discussion about the breaking of the Internet — Medium

Kik社はパッケージ取り下げの理由を、ユーザーの混乱を招くためとしているが、すでに公開されたパッケージの中身が変わる方が混乱を招くし、名前だけ見て中身を確認せずにパッケージを使うバカは混乱して当然だ。

npm運営は、これについて議論しているフォーラムを建設的ではないとして閉じるなど、その後の対応も疑問がある。

今回の件について、興味深い指摘がある。

NPM & left-pad: Have We Forgotten How To Program? | Haney Codes .NET

そもそも、leftpadの中身は10行程度のコードである。空行を抜けば、以下の通り。

module.exports = leftpad;
function leftpad (str, len, ch) {
  str = String(str);
  var i = -1;
  if (!ch && ch !== 0) ch = ' ';
  len = len - str.length;
  while (++i < len) {
    str = ch + str;
  }
  return str;
}

実に多くのパッケージが、このleftpadに依存している。しかし、この程度の関数は数分で書けるのだから、なんでわざわざ依存するんだ?

もっと憂うべきパッケージがある。isArrayだ。このパッケージは一日88万回もダウンロードされていて、2016年2月だけの一ヶ月間に1800万回もダウンロードされていて、72個ものNPMパッケージが依存している。

isarray

isArrayの中身はこうだ。

var toString = {}.toString;

module.exports = Array.isArray || function (arr) {
  return toString.call(arr) == '[object Array]';
};

結局、このコードは本質的にたった一行のコードである。

その他、is-positive-integerという整数が正の整数かどうか判定するパッケージがあるが、これも本質的には4行のコードである。ところが、このパッケージは昨日まで3個もの依存を持っていた(今は0個になっている)

なぜこんなにも多数のパッケージに依存をするのだ?

leftpad, isArray, isPositiveInteger程度、ググる時間を含めても5分程度で書けるはずである。書けない奴はそもそもコードが書けないと言っていい。NPM界隈の人間はコードが書けないのか?

今回の騒動で、以下のような面白いネタパッケージシステムが開発されている。

require-from-twitter

曰く、「Twitterには編集ボタンがないので、最適なJavaScriptモジュールをホストである」

このパッケージシステムを使うには、まずソースコードを自分でツイートして

https://twitter.com/rauchg/status/712799807073419264

しかる後に使う。


const leftPad = await requireFromTwitter('712799807073419264');
console.log(leftPad(1, 5));      // '00001'
console.log(leftPad(1234, 5));   // '01234'
console.log(leftPad(12345, 5));  // '12345'

Twitter社さえ信用すればよい。

ドワンゴ広告

ドワンゴの採用面接を受けると日本Node.jsユーザーグループの「元」代表の@mesoとお話ができるそうだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2015-08-13

Emscriptenがpthreadを実験的にサポート

Emscripten gains experimental pthreads support! - Google Groups

Emscrptenがpthreadを実験的にサポートしたそうだ。

JavaScript上でスレッドを実装する上で障害になるのは、スレッドに相当する方法が存在しないということだ。Web Workerは実行媒体ごとに隔離されて、メッセージパッシングで他の実行媒体と通信をする仕組みになっている。これは同じメモリに複数の実行媒体からアクセスするというスレッドとは異なり、プロセスに近い。

現在、JavaScript上で共有メモリを扱えるようにしようというドラフト規格、SharedArrayBufferが議論中であり、Firefox Nightlyが実験的実装を進めている。この機能を用いて、Emscriptenでpthreadを実験的に実装したそうだ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2015-05-20

ask.fmの回答を簡単にするブラウザー拡張を書いた

Big Sky :: 江添さんに簡単に質問出来るコマンドを golang で書いた。

珍しくフルチンではないmattnさんが、ask.fmの私のアカウントに質問を投稿するCLIのツールをgoで書いたようだ。そのためと、しばらく回答していなかったため、ask.fmが大量のオヤジギャグを含む質問で埋まってしまった。

ask.fmをブラウザーから閲覧して質問に答えるのはいいが、UIに不満がある。マウスを使わなければ質問に答えられない。このため、キーボードだけで質問に答えられるよう、ブラウザー拡張を書いた。

https://github.com/EzoeRyou/askfm-mod

質問の一覧でショートカットキーを押すと、最新の質問の回答URLに移動する。回答を入力してショートカットキーを押すと、回答ボタンをクリックする。何も回答を入力しないままショートカットキーを押すと、「質問ではない」と回答する。

本来なら、こういうブラウザー拡張はもっと早く書くべきだったのだが、ダルいためなかなか作成に踏みきれずにいた。

ドワンゴ広告

久しぶりにChromiumの拡張を作ったら、manifest.jsonのフォーマットが微妙に変わっていた。こんなことより、早くC++の論文集を読まなければならないのだが。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-04-23

JavaScriptのオブジェクト初期化子

JavaScriptでは、オブジェクトをリテラル風に式の中に書くことができる。これは、オブジェクト初期化子(Object Initialiser)とか、オブジェクトリテラル(Object Literal)と呼ばれている。その文法は、{ }の中にプロパティを記述する。

var a = {} ;
var b = { PropertyName : AssignmentExpression } ;
var c = { A : 1, B : 2, C : 3 } ;

プロパティ名とその値のペアを、コロンで区切って指定する。そしてカンマで区切る。

オブジェクト初期化子は、{}内の最後をカンマで終わらせることもできる。

{ A : 1, } ;

これは、やや気持ち悪い文法だ。

PropertyNameには、識別子と文字列リテラルと数値リテラルを書くことができる。

var x = {
// 識別子
IdentiferName : 0,
// 文字列リテラル
"StringLiteral" : 0,
// 数値リテラル
3.14 : 0 
} ;

さて、オブジェクト初期化子のプロトタイプに文法には、もうひとつ、getter/setter、あるいは、アクセッサーなどと呼ばれているものを記述する文法がある。文法は関数式に似ているが、functionキーワードのかわりに、get/setを用いる。

function X( val )
{
    this.value = val ;
}

X.prototype = {
    get value() { return this._value ; }
    set value( val ) { this._value = val ; }
} ;

var x = new X(0) ;
x.value ; // 0
x.value = 10 ;
x.value ; // 10
x.value += 10 ;
x.value ; // 20 

アクセッサーは、通常の関数呼び出しの文法を使わずに、同じ識別子で、値の設定と取得を、単なる参照と代入というわかりやすい文法で行うことができる機能である。これは、例えば以下のように書くより、格段にコードがわかりやすくなる。


function X( val )
{
    this.value = val ;
}

X.prototype = {
    function get_value() { return this.value ; }
    function set_value( val ) { this.value = val ; }
} ;

var x = new X(0) ;
x.get_value() ;
x.set_value(10) ;
x.get_value() ;
x.set_value( x.get_value + 10 ) ;
x.get_value() ;

ちなみに、Where's Walden? » More SpiderMonkey changes: ancient, esoteric, very rarely used syntax for creating getters and setters is being removedによれば、アクセッサーの文法には、実に様々な歴史的な非標準の方言があったようだ。特にMozillaのものだが。

まず、__defineGetter__/__define_Setter__がある。これは、Object.definePropertyを使うべきである。

かつて、SpiderMonkeyのJavaScriptのパーサーに問題があったため、以下のようなコードが通ってしまっていた。

var x = { get a b() { return "get" ; } } ;

また、アクセッサーの生みの親であるNetscapeの当初の文法は、以下のものであったらしい。

function g() { print("gotten!"); return "get"; }
var o1 =
  {
    property getter: g,
    property setter: function(v) { print("sotten!  " + v); }
  };
var v1 = o1.property; // prints "gotten!", v1 === "get"
o1.property = "new"; // prints "sotten!"

SpiderMonkeyはこれをしばらくサポートしていた。

また、アクセッサープロパティを付け加えるSpiderMonkey独自の文法として、以下のようなものもあったらしい。

var o = {};
o.property getter = function() { print("gotten!"); return "get" };
o.property setter = function() { print("sotten!"); };
var v = o.property; // prints "gotten!", v === "get"
o.property = "new"; // prints "sotten!"

うーん・・・。

SpiderMonkeyの独自文法はまだある。

getter function foo() { return "foo getter"; };
var v = foo; // "foo getter"
var q = setter function bar(v) { };

うーむ。

そういえば、strict modeのとき、PropertyAssignmentの中のPropertySetparameterListの識別子として、"eval"と"arguments'が現れると文法エラーというのは、どういうことだろう。コード例で言えば、以下のようなものだが。

"use strict" ;

// SyntaxError
var x = { set setter( eval ) { } } ;

なぜ、数あるキーワードの中でevalとargumentsだけが特別に禁止されているのか。ちょっと調べただけでは出てこない。もうすこし規格を読み進める必要がありそうだ。

ドワンゴ広告

この記事はドワンゴ勤務中に、十分な昼寝とカタンをした後に、書かれた。睡眠は重要である。カタンも重要である。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-04-21

JavaScriptの誕生と終焉

The Birth & Death of JavaScript — Destroy All Software Talks

あの、Watのスピーカーとして有名なGary Bernhardtが、JavaScriptの誕生と終焉についてスピーチしている。

このスピーチは、2040年に行われているという設定である。JavaScriptが10日でやっつけ設計されたというところから始まり、JavaScriptが開発された地は、すでに放射能汚染されているという、2040年からみた歴史的事実を交えつつ、話は続く。

JavaScriptはあまりにも一般化してしまったため、皆JavaScriptで書くようになった。ただし、JavaScriptは遅いので、JavaScriptをネイティブコードにコンパイルしやすいようにする制限的な記法が流行した(整数型でいいところには、0をビット列論理和することにより、整数型であることのアノテーションとするなど)。

そして、他の言語からJavaScriptを生成することが流行した。もはや、C言語からすらJavaScriptを生成できる。

次第に、JavaScriptは移植性の高い共通のアセンブリの地位を確立させていく。

そして、核戦争が起きた。オーストラリアの辺境にでも住んでいる変人でもなければ、10年ほどプログラミングなど出来ない状況に陥る。

そして、ようやくプログラミング可能なほど状況が落ち着いたとき、人々はプログラミングできない間でも、潜在意識の中で、思案を続けていた。

そもそも、CコードがJavaScriptにコンパイルできるのである。OSはなんで書かれているか? Cである。OSをJavaScriptにコンパイルすればいいではないか。

OSは、ハードウェアの特権モードの支援を受けて、ユーザースペースのプロセスを、お互いに干渉できないような隔離を保証する。この特権モードの切り替えは、非常に高くつく。しかし、Webブラウザーはタブでソフトウェア的に隔離を実装しているではないか。

なんと2040年では、JavaScriptは、極めて移植性の高い共通のアセンブリ言語として君臨している。もう移植性のない点でバラバラのハードウェアについて考える必要はないのだ。JavaScriptで動作する分、2割ほど遅くなるが、ハードウェアの特権モードを多用しない分、2割ほど速くなる。掛け算がどのように働くかということをかんがえれば、0.8 * 1.2 = 0.96であり、ネイティブで実行するよりも多少遅くはなるのだが、これは許容範囲である。

そして、JavaScriptは死んだ。JavaScriptは使われているが、もはや誰もJavaScriptを直接書くことはない。

そういった内容の、架空のジョークスピーチだ。とても面白い。

ドワンゴ広告

この記事はJavaScriptと関係があるので、ドワンゴ勤務中に書いた。超チューニング祭に役立つ記事ではなさそうだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

JavaScriptの配列初期化子

ECMAScript Edition 5.1を§11まで読み進めた。§11は、式だ。ようやく面白くなってきた。

§10は、この後の文面で使いまわすための、擬似的な処理を定義している。

さて、いよいよ具体的にコードとして書く、式のセクションを読んでいる。なかなか楽しいが、配列初期化子の文法が興味深かった。

配列初期化子、あるいは配列リテラルは、[ ]の中に要素を書く。

// 結果は要素数4の配列、[ 1, 2, 3, 4 ]
[ 1, 2, 3, 4 ] ;

配列初期化子には、Elisionという文法があり、途中の要素を省略できる。省略した要素は、undefinedである。

// 結果要素数4の配列、[ 1, undefined, 3, 4 ]
[ 1, , 3, 4 ] ;

なるほど、これはよく分かる。しかしよくわからないのは、「Elisionが配列の最後に使われた時には、配列の長さに寄与しない」という文面だ。つまり、最後のElisionは、無視されるのだ。

// 結果は3
[ 1, 2, 3 ].length ; 
// 結果は3
[ 1, 2, 3, ].length ;

たいていの言語ならば、文法違反とするところだが、実に不思議で例外的な文法だ。

しかし、それだけではない。要素が任意個のElisionだけの場合の文法も特別に定義されていて、その場合は、末尾のElisionも配列の長さに寄与するのだ。

[].length ; // 0
[,].length ; // 1, [undefined]
[1,].length ; // 1, [1, undefined]
[,,].length ; // 2, [undefined, undefined]
[1,,].length ; // 2, [1, undefined]

気持ち悪い。極めて気持ち悪い。例外に例外を重ねた文法で気持ち悪い。

さて、次はオブジェクト初期化子だが、どうもこれも、文法が気持ち悪そうだ。

文法の汚さ、パースしにくさでいえば、C++は悲惨なのだが、しかし、このような不思議な文法は多くない。JavaScriptの文法は気持ち悪い。

それでも、JavaScriptの文法や思想は、いまさら言うことではないが、面白い。

ドワンゴ広告?

この記事は超チューニング祭に向けてドワンゴ勤務中にECMAScript Edition 5.1を読みながら書いた。

そもそも、この超チューニング祭というのは、ユーザーによる企画だそうである。実は筆者も詳しいことを知らない。公式サイトが更新されて、基本ルールが追加されたが、この更新情報も事前事後に知らさるような特別なはからいは一切ない。そのため当日は、ドワンゴ社員であることによる不公平な情報差は発生しないだろうから安心してよろしい。

ところで、その更新されたルールによれば、当日編集できるソースコードは、HTML, CSS, JavaScriptだという。

「超チューニング祭 ~ニコニコを超快適にしてみた~ in ニコニコ超会議3」の問題点 - Webサイトパフォーマンスについてで指摘されているように、ボトルネックの大半はフロントエンドにないというのは、実際その通りだろう。複数のCSSやJavaScriptを結合したり、最小化したりといった小手先の技術は、小さな最適化に過ぎない。

では、勝利を狙うカギは、パフォーマンス以外の評価点、すなわちUIデザインだろうか。スマートフォン向けのデザインは、小さな画面サイズのため、とても単純にならざるを得ず、差別化を行いにくい。

ところで、現在、自由なスマートフォンがないので、筆者は携帯電話を所有していない。当日は極めて厳しい戦いを強いられることになりそうだ。

そして、そろそろ「広告」の定義について根本的な疑問が生じている。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-04-17

JavaScriptの自動セミコロン挿入

JavaScriptでは、多くの文は、セミコロンという終端記号を明示的に記述して、文の終わりを示す。

var i = 0 ;
++i ;
--i ;

しかし、JavaScriptでは、一部の文脈で、セミコロンの省略が許されている。あたかも、セミコロンが自動的に挿入されたかのように振る舞う。これを、自動セミコロン挿入(Automatic Semicolon Insertion)

ECMA-262 Edition 5.1 §7.9が規定する、自動セミコロン挿入の定義を、本記事では解説する。

まず、三つの基本的なルールがある。

  • プログラムを左から右にパースした時に、文法上許されないトークン(反則トークン, offending token)があった場合、以下の二つの条件のうちどちらかひとつ、もしくは両方を満たせば、セミコロンが自動的に挿入される。

    • 反則トークンと前のトークンが、ひとつ以上の行終端子で分かたれている場合

      // 例
      var x
      x
      x
      x
      

      これは、以下のようにセミコロンが自動挿入される。

      // 自動セミコロン挿入後
      var x ;
      x ;
      x ;
      x ;
      
    • 反則トークンが}である場合

      // 例
      function f(){ var x }
      
      // 自動セミコロン挿入後
      function f(){ var x ; }
      
  • プログラムを左から右にパースした時に、トークン列の最後に到達したが、正しい文法を構築できない場合、トークン列の最後にセミコロンが自動的に挿入される。

    // 例
    var x
    
    // 自動セミコロン挿入後
    var x ;
    
  • インクリメント、デクリメント、continue、break, return, throwの間で、行終端子が許されていない場所に行終端子がある場合、セミコロンが自動的に挿入される。

    LeftHandSideExpression [行終端子不許可] ++
    LeftHandSideExpression [行終端子不許可] --
    continue [行終端子不許可] Identifier ;
    break [行終端子不許可] Identifier ;
    return [行終端子不許可] Expression ;
    throw [行終端子不許可] Expression ;
    

最後のルールは、たとえば以下のようになる。

var i = 0 ;

i // 自動セミコロン挿入
++ ; // 文法エラー
i // 自動セミコロン挿入
-- ; // 文法エラー

function f()
{
    return // 自動セミコロン挿入、undefinedが返される。
    {
    // JSON的な何か
    } ;
}

ただし、自動挿入したセミコロンが空文に解釈される場合と、for文のヘッダーの中では、自動セミコロン挿入は行われない。

// 空文に解釈される場合
if( cond )
else

これは、もし自動セミコロン挿入が行われるとするならば、以下のようになる。

// 空文に解釈される場合
if( cond ) ;
else ;

このセミコロン挿入は、どちらも空文となるので、自動セミコロン挿入は行われない。

for文のヘッダーとは、for ( ... ; ... ; ... )のことだ。これにも自動セミコロン挿入は行われない。

さて、なぜ自動セミコロン挿入などという規則が存在するのか。思うに、ECMAScriptというのは、規格があって、しかる後にJavaScriptとして実装された言語でではない。JavaScriptという実装だけが先行して、あとからデファクトスタンダードとなった挙動を、ECMAScriptとして追認した形なのだ。規格の責任ではない。無秩序に進化した実装の歴史的経緯の問題である。したがって、既存の実装の挙動を、なるべく正確に規格に落としこんでいる。ECMA-262 Edition 5.1は、既存の実装の挙動を規格に落としこむという点で、非常にいい仕事をしたと思う。文面は読みやすい。JavaScriptは、C++より落とし穴が多い言語であるが、ECMA-262 Edition 5.1で、だいぶ救われている。

なお、規格では、自動セミコロン挿入には頼るべきではなく、明示的にセミコロンを書くべきだとしている。

ドワンゴ広告

この記事は、ドワンゴで最も怠惰な社員である筆者が、出社早々To Court The Kingで遊んだあとに、超チューニング祭に向けて準備をするふりをして書いた。まだバレていないようだ。

そういえば、昨日、珍しく時間の指定されて参加する必要のある社内会議があったので、予定時間の5分前に会議室に行った所、まだ誰も集まっていないどころか、会議室が別の会議で使用中であった。仕方がないので、一旦引き上げて、予定時間の2分後に会議室に行った所、前の会議の参加者は引き上げた上に、すでに全員集まって着席していた。一体、わずか7分間の間に何があったのか。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-04-16

JavaScript規格の正規表現リテラルの文面の疑問点

JavaScript規格、ECMA-262 Edition 5.1を読み進めていて、以下の文面が気になった。

A regular expression literal is an input element that is converted to a RegExp object (see 15.10) each time the literal is evaluated. Two regular expression literals in a program evaluate to regular expression objects that never compare as === to each other even if the two literals' contents are identical.

正規表現リテラルは、リテラルが評価されるごとに、RegExpオブジェクトに変換される入力要素である。プログラム中の二つの正規表現リテラルは、たとえ二つのリテラルの中身が同一であっても、===と比較されることのない正規表現をオブジェクトに評価される。

§7.8.5 Regular Expression Literals

つまりは、/./ === /./ はfalseになるということだ。正規表現リテラルが評価されるごとに別のオブジェクトになるということは、以下のようになる。


for ( var elem in [ true, false ] )
{
    var r = /./ ; // ひとつの正規表現リテラル 
    if ( elem )
        var a = r ;
    else
        var b = r ;
}

a === b ; // false

なるほど、確かに複数回評価されている。

しかし、文面では二つの正規表現リテラルとあるが、このプログラム中に、正規表現リテラルはひとつしかない。ひとつの正規表現リテラルが二回評価されるだけだ。と、屁理屈めいた疑問も生ずる。

筆者が規格を読むときは、文面は全て間違っているという前提で読むので、このような屁理屈のような疑問が生ずる。

ドワンゴ広告

この記事はドワンゴ勤務中にやんごとなき理由により自分の机を離れて書いた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-04-14

JavaとJavaScriptの違い

JavaとJavaScriptには、Unicode escape sequenceというものがある。どちらも同じ文法で、\uに続いて4文字の16進数文字を指定することで、Unicode Code Pointを指定できる。あたかも、Unicode Code Pointを記述したかのように振る舞う。

ところで、JavaとJavaScriptは、このUnicodeエスケープシーケンスの使い方が異なる。例えば、行終端文字\u000Aを、以下のように書く。

// これは\u000Aコメント

これは、JavaScriptで解釈すると、以下のようになる。

// これは\u000Aコメント

以下は、Javaによる解釈である。

// これは
コメント

Javaでは、Unicodeエスケープシーケンスが、実際に行終端文字として扱われてしまう。したがって、行終端文字以降が一行コメントからはみ出してしまう。

これは、文字列リテラルの中でもそうである。

"これは\u000A文字列リテラル" ;

というコードは、Javaでは

"これは
文字列リテラル" ;

と解釈される。Javaの文字列リテラルは、途中に改行文字を記述してはならないので、これはエラーとなる。Javaで文字列リテラルの中に、リテラルの値として改行文字を入れたい場合は、\nなどと書かなければならない。

Javaは謎すぎる。ますますJavaはクソであるという認識を新たにした。

というわけで、ECMA-262 Edition 5.1を読んでいるが、まず、文法記法の丁寧な定義が書いてある。これはとても親切だ。ただし、丁寧な定義と引き換えに、いろいろと文法記法が複雑になっている。これは、JavaScriptのデファクトスタンダードな文法を、後から追認する形で規格化したので、どうしてもこのような複雑な記法にならざるを得ないのだろう。例えば、改行が意味を持つ文脈など。

次はLexical Conventionsだ。

ドワンゴ広告

この記事は超チューニング祭のために勤務中にECMA-262 Edition 5.1を読んでいて興味深かったので書いた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2013-10-16

JavaScriptのよるOpenRISCエミュレーター上でGNU/Linux/XorWaylandを動かすデモ

jor1k: OpenRISC OR1K Javascript Emulator Running Linux

Github: s-macke/jor1k

JavaScriptでOpenRISCをエミュレートして、その上でGNU/Linuxを動かし、さらにXやWaylandまで動かしてしまうというふざけたデモ。

筆者の環境では、0.3fpsほどで動作した。

2012-08-24

V8ベンチマークのOctaneに新しいベンチが5つ追加

The Benchmark - Octane — Google Developers

Chromiumで使われているJavaScriptの実装V8のベンチマーク集、Octaneに、新しいベンチが5つ追加されている。

  • pdf.js

    MozillaのJavaScript実装によるPDFリーダーから拝借したコード。

    mozilla/pdf.js @ GitHub

  • Mandreel

    3D Bullet Physics EngineをC++からJavaScriptに移植したコード。

    Game Physics Simulation

  • GB Emulator

    詳しい参照先不明。有名なコンソール機のエミュレーターで、しかも3Dシミュレーションを行うだとか。名前からするとゲームボーイが思い浮かぶし、実際にJavaScriptで実装されたゲームボーイエミュレーターはあるが、3Dとは一体。

  • Code loading

    巨大なJavaScriptのコードをロードして、すぐに実行するもの。コードは、ClosureやjQueryのテストがベースになっているらしい。

  • Box2DWeb

    有名なBox2DWebを元にしたベンチマーク。

    box2dweb - Box2DFlash port to javascript - Google Project Hosting

2012-03-15

Javascriptを完全に理解しているための必須要件

大学で日本におけるエンジニアの地位の低下を象徴している求人見つけた [必須条件] ... - HAMPAD

必須条件がJavascriptを完全に理解していることとはすばらしい。思うに、Javascriptを完全に理解していると主張するためには、少なくとも以下の条件は最低でも満たしているはずである。

  • ECMA-262 5thの全文を暗唱
  • 過去にV8程度のパフォーマンスをもつJavascriptライブラリを実装
  • Brendan EichやJohn ResigやDouglas Crockfordとは、ファーストネームで呼び合う仲である

そんな人材がゴロゴロしている職場か。なかなか楽しそうだ。

2011-11-26

JavaScriptの難読化におすすめのサービス

aaencode - Encode any JavaScript program to Japanese style emoticons (^_^)

alert("Hello, JavaScript")

という何の変哲もないJavaScriptのコードが、

゚ω゚ノ= /`m´)ノ ~┻━┻   //*´∇`*/ ['_']; o=(゚ー゚)  =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];(゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] + ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];(゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\'; (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];(゚Д゚) [゚o゚]='\"';(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+(゚Д゚)[゚o゚]+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚o゚]) (゚Θ゚)) ('_');

という、訳のわからないコードに変換される。

2011-07-14

chrome extensionのXMLHttpRequestが改良された

Chromium Blog: Chrome Extensions: Now with more powerful scripts and improved proxy management.

なんと、content scriptからクロスドメインなXMLHttpRequestができるようになった。これで、いちいちマヌケにもbackground pageを介してメッセージのやり取りをする必要はない。パフォーマンスも向上する。

この仕様は常々疑問だったのだ。background pageといえども、manifesto.jsonに指定したpermissionを無視したXMLHttpRequestはできない。それならば、content script内で、permissionを考慮したクロスドメインなXMLHttpRequestができてもしかるべきだ。何しろ、こちとらはエクステンションなのだ。

さっそく、個人的に作って使っているエクステンションを書き換えたところ、体感できるほどパフォーマンスが向上した。

ちなみに、ユーザー側の利点としては、Greasemonky用のスクリプトで、GM_xmlhttpRequestを使っているという理由で今までは動かなかったスクリプトが、chromeでも動くようになる。

2011-05-17

JavascriptによるPCエミュレーター

Javascript PC Emulator
Javascript PC Emulator - Technical Notes

これは、QEMU作者による、Javascriptで書かれたPCエミュレーターである。その上で、Linuxカーネルを動かしている。どうも、Chrome 12では、バグにより動かないようだ。Firefox 4なら問題なく動く。にわかに信じがたい。

技術メモを読むとわかるが、これはかなり限定的なエミューレションである。しかし、Linuxカーネルを動かすには十分である。

エミュレートしているのは、主に以下のチップである。

  • a 32 bit x86 compatible CPU
  • a 8259 Programmble Interrupt Controller
  • a 8254 Programmble Interrupt Timer
  • a 16450 UART.

エミュレートされているx86 CPUには、FPUがない。しかし、LinuxにはFPUエミュレーションがあるので、問題ない。

もちろん、viやemacsも起動するし、TinyCがあるので、なんとC言語によるプログラミングも可能である。

まえに、Javascriptで書かれたファミコンエミュレーターをみたとき、誰かがx86エミュレーターも書くんじゃないだろうかと予想した。まさか、こんなに早く、実物を目にするとは思わなかった。

ところで、JavascriptにTyped Arrayというドラフト規格ががあることを初めて知った。これは良さそうだ。