Posted by & filed under いろいろ.

このエントリーを含むはてなブックマークはてなブックマーク - NashornでもE4Xを使いたい このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - NashornでもE4Xを使いたい Share on Tumblr Digg This

Nashornの字句解析のソースを見るとnashorn.lexer.xmlliteralsというのがあります。

XMLリテラル?…XML?…!?

E4X!E4Xじゃないか!

試してみました。
https://gist.github.com/tuchida/9796167

nashorn.lexer.xmlliteralsなし

$ jdk1.8.0/bin/javac E4X.java && jdk1.8.0/bin/java E4X
E4X: null
javax.script.ScriptException: <eval>:1:0 Expected an operand but found <
<xml>xml</xml>
^ in <eval> at line number 1 at column number 0
at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:564)
at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:610)
at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:597)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:524)
at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:194)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
at E4X.main(E4X.java:11)
Caused by: jdk.nashorn.internal.runtime.ParserException: <eval>:1:0 Expected an operand but found <
<xml>xml</xml>
^
at jdk.nashorn.internal.parser.AbstractParser.error(AbstractParser.java:258)
at jdk.nashorn.internal.parser.AbstractParser.error(AbstractParser.java:243)
at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:2788)
at jdk.nashorn.internal.parser.Parser.expression(Parser.java:2888)
at jdk.nashorn.internal.parser.Parser.expressionStatement(Parser.java:1017)
at jdk.nashorn.internal.parser.Parser.statement(Parser.java:852)
at jdk.nashorn.internal.parser.Parser.sourceElements(Parser.java:693)
at jdk.nashorn.internal.parser.Parser.program(Parser.java:631)
at jdk.nashorn.internal.parser.Parser.parse(Parser.java:213)
at jdk.nashorn.internal.parser.Parser.parse(Parser.java:188)
at jdk.nashorn.internal.runtime.Context.compile(Context.java:936)
at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:917)
at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:406)
at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:608)
... 5 more

nashorn.lexer.xmlliteralsあり

$ jdk1.8.0/bin/javac E4X.java && jdk1.8.0/bin/java -Dnashorn.lexer.xmlliterals=true E4X
E4X: true
java.lang.NullPointerException
at jdk.nashorn.internal.codegen.MethodEmitter.convert(MethodEmitter.java:1560)
at jdk.nashorn.internal.codegen.CodeGenerator.enterLiteralNode(CodeGenerator.java:1432)
at jdk.nashorn.internal.codegen.CodeGenerator.access$300(CodeGenerator.java:154)
at jdk.nashorn.internal.codegen.CodeGenerator$1.enterLiteralNode(CodeGenerator.java:473)
at jdk.nashorn.internal.ir.LiteralNode.accept(LiteralNode.java:210)
at jdk.nashorn.internal.codegen.CodeGenerator.load(CodeGenerator.java:424)
at jdk.nashorn.internal.codegen.CodeGenerator.load(CodeGenerator.java:403)
at jdk.nashorn.internal.codegen.CodeGenerator$8.evaluate(CodeGenerator.java:2471)
at jdk.nashorn.internal.codegen.CodeGenerator$Store.store(CodeGenerator.java:3206)
at jdk.nashorn.internal.codegen.CodeGenerator.enterASSIGN(CodeGenerator.java:2476)
at jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor.enterBinaryNode(NodeOperatorVisitor.java:117)
at jdk.nashorn.internal.ir.BinaryNode.accept(BinaryNode.java:168)
at jdk.nashorn.internal.codegen.CodeGenerator$1.enterDefault(CodeGenerator.java:479)
at jdk.nashorn.internal.ir.visitor.NodeVisitor.enterBinaryNode(NodeVisitor.java:178)
at jdk.nashorn.internal.ir.BinaryNode.accept(BinaryNode.java:168)
at jdk.nashorn.internal.codegen.CodeGenerator.load(CodeGenerator.java:424)
at jdk.nashorn.internal.codegen.CodeGenerator.load(CodeGenerator.java:359)
at jdk.nashorn.internal.codegen.CodeGenerator.enterDISCARD(CodeGenerator.java:2345)
at jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor.enterUnaryNode(NodeOperatorVisitor.java:57)
at jdk.nashorn.internal.ir.UnaryNode.accept(UnaryNode.java:124)
at jdk.nashorn.internal.codegen.CodeGenerator.enterExpressionStatement(CodeGenerator.java:857)
at jdk.nashorn.internal.ir.ExpressionStatement.accept(ExpressionStatement.java:66)
at jdk.nashorn.internal.ir.Node.accept(Node.java:291)
at jdk.nashorn.internal.ir.Block.accept(Block.java:143)
at jdk.nashorn.internal.ir.LexicalContextNode$Acceptor.accept(LexicalContextNode.java:57)
at jdk.nashorn.internal.ir.Block.accept(Block.java:361)
at jdk.nashorn.internal.ir.FunctionNode.accept(FunctionNode.java:297)
at jdk.nashorn.internal.ir.LexicalContextNode$Acceptor.accept(LexicalContextNode.java:57)
at jdk.nashorn.internal.ir.LexicalContextExpression.accept(LexicalContextExpression.java:46)
at jdk.nashorn.internal.ir.FunctionNode.accept(FunctionNode.java:49)
at jdk.nashorn.internal.codegen.CompilationPhase$8.transform(CompilationPhase.java:379)
at jdk.nashorn.internal.codegen.CompilationPhase.apply(CompilationPhase.java:513)
at jdk.nashorn.internal.codegen.Compiler.compile(Compiler.java:358)
at jdk.nashorn.internal.runtime.Context.compile(Context.java:960)
at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:917)
at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:406)
at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:608)
at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:597)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:524)
at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:194)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
at E4X.main(E4X.java:11)

nashorn.lexer.xmlliteralsありだとシンタックスエラーにならずコード生成部分でヌルポになりました。ソースを追ってみるとトークンの生成はするのですが(valueOfXMLのコメントが「Convert a regex token to a token object.」なのが微笑ましいですね)、コード生成時にXMLTokenを見てる箇所がありません。

はー、RhinoかわいいよRhino。


関連文書:

  • 関連文書は見つからんがな

Posted by & filed under 勉強会.

このエントリーを含むはてなブックマークはてなブックマーク - 社内Java8勉強会 ラムダ式とストリームAPI このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - 社内Java8勉強会 ラムダ式とストリームAPI Share on Tumblr Digg This

先週Java8がリリースされましたが、さっそく社内での開発でも使うことになりそうです。

というわけで、Java8の目玉機能であるラムダ式とストリームAPIについて、社内勉強会を開催しました。

普段の社内勉強会よりも参加者数が多くて、みんなの関心の高さが伺えますね。

 

ラムダ式とストリームAPIは、他のプログラミング言語とだいたい似たようなものだろうと思っていたのですが、調べてみると意外とJava特有のことが多くて面白かったです。


関連文書:

  • 関連文書は見つからんがな

Posted by & filed under 開発.

このエントリーを含むはてなブックマークはてなブックマーク - Java8のラムダ式の説明に対するつっこみを受けて このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - Java8のラムダ式の説明に対するつっこみを受けて Share on Tumblr Digg This

先日の記事に宮川さんからつっこみが入りました。

http://d.hatena.ne.jp/miyakawa_taku/20140315/1394902012

ありがたいことです。やはり情報というのはどんどん公開すべきです。

リンク先を読まない人のために書いておくと、自分が書いた「Java8のラムダ式は(関数型インターフェースの)オブジェクトを生成しない」は間違いで、仕様上は「Evaluation of a lambda expression produces an instance of a functional interface」です、というつっこみです。

この記述は知りませんでした。

「an instance of a functional interface」をオブジェクトと言い換えていいかは多少迷います。オブジェクトという用語の定義次第だからです。個人的には、参照のとれる実体をオブジェクトと呼んでいいと思うので、これをオブジェクトと言い換えるのにそんなに抵抗はありません。とは言え、produce an instanceとcreate an objectを同じ日本語にするのは少し抵抗があります。

なので、昨日の記事の発言は「OpenJDK Java8のラムダ式は(関数型インターフェースの)オブジェクトをnewしない」に訂正します。newは単に対応するバイトコードのことです。用語に解釈の余地がありません。

ちなみに、「Java8のラムダ式は(関数型インターフェースの)オブジェクトを生成しない」と書いた理由のひとつは、new呼び出しのないバイトコードを見ての判断ですが、もうひとつの理由としてラムダ式の中に書いたthis参照の動きがあります。と言うのも、ラムダ式の中のthis参照はエンクロージングオブジェクトを参照するからです。この動作が、(InvokeDynamicを使うか否かの)実装依存だとまずいはずです。

仕様から探すと、「Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body are the same as in the surrounding context (except that lambda parameters introduce new names).」が該当するようです。


関連文書:

  • 関連文書は見つからんがな

Posted by & filed under いろいろ.

このエントリーを含むはてなブックマークはてなブックマーク - そろそろはてなブログのjsについて一言いっておくか このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - そろそろはてなブログのjsについて一言いっておくか Share on Tumblr Digg This

※本記事は最後まで読まないと誤解されかねない内容を含むため、Web広告に敵愾心を抱いてる方、プライバシやくざの方などは閲覧をご遠慮ください

http://hatenablog.com/js

Hatena.Diary.setupTrackとかHatena.Diary.trackEventNowとかあるのにnavigator.doNotTrackを見てないのが気になりました。

別にこのことを批判したいわけではありません。ぱっと見た感じ表示しているURLやreferrerなどの一般的なサーバーのアクセスログに記録される情報だったり、表示にかかった時間やスクリプトエラーなどのセンシティブでない情報を記録してるだけに見えます。Do Not Trackがこの手のものまで禁止してるかも知りません。

ただ今回の件ではてなブックマークボタンのトラッキングの件にふれてる人が見当たらなかったので一言いっておきたくなりました。minifyやコメント削除をするとこういったことのチェックが難しくなります。まあトラッキングだけなら通信見ればわかるし、minifyされててもClosure CompilerのADVANCEDモードで鍛えられたおかげである程度は読めるけど。


関連文書:

  • 関連文書は見つからんがな

Posted by & filed under 開発.

このエントリーを含むはてなブックマークはてなブックマーク - Java8の日付および時刻処理(Date/Time API(JSR-310))の紹介と利用指針 このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - Java8の日付および時刻処理(Date/Time API(JSR-310))の紹介と利用指針 Share on Tumblr Digg This

Java8のリリースが近づいています。Java8と言うとラムダ式のほうが有名ですが、多くの人がブログに書きそうなので、地味なDate/Time API(JSR-310)のほうを説明します。
ひとつだけラムダ式について言及しておくと、「ラムダ式は(関数型インターフェースの)オブジェクトを生成する」と説明している文章があったら、その文章は怪しいので疑いの目で読んでください。実際にはラムダ式はオブジェクト生成のコードにはならないからです(InvokeDynamicの呼び出しコードになります)。

さて、Date/Time API(JSR-310)の話です。
Javaの新しい日時処理(日付処理および時刻処理)のAPIです。結構、複雑です。過剰設計という批判もあるようです。自分自身、まだそこまでの判断はできません。自分が言えるのは、日時処理はそもそも本質的に複雑だという経験です。ざっと思いつくだけでも日時処理が複雑になる要因として次のような思いつきます。

  • そもそも一貫性がない(月ごとに日数が異なる)
  • 様々な基数(12進数、60進数、7進数?(曜日))
  • 何の法則もない祝日
  • 何の法則もない年号
  • 複雑さに輪をかけるタイムゾーン
  • 複雑さに輪をかけるうるう年
  • 複雑さに輪をかける夏時間

うんざりします。

Date/Time APIというフレームワークに載ってラクができるならそれに越したことはありません。

Date/Time APIの具体例の前に用語定義をします。

基本概念の用語定義

時刻 時間軸上のある瞬間の値。タイムゾーンと関係あり。タイムゾーン非依存の時刻をエポック値と定義(後述)
時間 時刻の差の値。タイムゾーンと無関係
日時 時刻を人間のために年月日時分秒で表現したもの
日付 時刻のうち年月日

可能な演算

時刻と時刻 減算(結果は時間)
時間と時間 加算と減算(結果は時間)
時刻と時間 加算と減算(結果は時刻)

コンピュータのための概念の用語定義

エポック値 エポック時刻(UTC1970年1月1日0時)からの経過時刻。タイムゾーンと無関係

人間のための概念の用語定義

UTC日時 時刻をUTCで表記した日時。エポック値から一意に決まるので相互変換可能
ローカル日時 時刻を特定のタイムゾーンで表記した日時。エポック値とタイムゾーンから決まる
ラベル日 タイムゾーンと無関係な日(例: 12月25日はクリスマス)。厳密には時刻ではないので時刻(UTC日時、ローカル日時)と演算してはいけない
期間 年月日時分秒で表記した時間(例: 1年、3ヶ月)
年号 西暦や和暦などの年表記
タイムゾーン 時差

Date/Time APIに話を戻します。
Date/Time APIでローカル日時を表現しようとすると、LocalDateTime、OffsetDateTime、ZonedDateTimeの3つのクラスの候補があります。どれを使えばいいか迷います。可能か否かで言うとどれでも可能だからです。
まず、LocalDateTimeを使う選択をした場合、別途、タイムゾーンを管理する必要があります。とは言え、普通、国際化したプログラムであれば、利用ユーザのプリファレンスなどでそのユーザのタイムゾーン設定があるはずです。そのタイムゾーン情報をユーザコンテキストで持っていれば、LocalDateTimeで充足します。
一方、OffsetDateTime、ZonedDateTimeのふたつは、それ自体がタイムゾーンを持ちます。OffsetDateTimeは、元々、SQLやXMLなどの外部処理用らしいので、それ限定で良いかと思います。
そうなると、LocalDateTimeとZonedDateTimeのどちらを使うかに話が集約されます。
個人的にはZonedDateTimeを推します。別途ユーザコンテキストなどに持つタイムゾーン情報と冗長管理になりますが、どうせタイムゾーンが一緒でないと意味のないローカル日時であれば一緒のクラスにするほうが安全だと思うからです。

java.timeパッケージのクラスの説明と利用指針

Instant 時刻。UTC日時に使える
Duration 時間
Period 期間
ZoneId タイムゾーン(名前ベース)
ZoneOffset タイムゾーン(値ベース)。あまり使う機会はないかも
LocalDate ラベル日として使える(年号取得やうるう年判定に使える)
LocalTime タイムゾーンを気にしない単なる時刻処理クラスとして使える
LocalDateTime 通常の日時に使うのは危険(タイムゾーンなしの時刻はバグの元)。ラベル時刻(全世界同時刻)のためには使える
ZonedDateTime タイムゾーンありの日時。通常の日時に使う
OffsetTime 簡易版タイムゾーンありの時刻。外部処理用(SQLやXML)
OffsetDateTime 簡易版タイムゾーンありの日時。外部処理用(SQLやXML)

その他パッケージのクラスの説明

TemporalAdjusters 強力な日付演算(月末、直近の日曜日など)ユーティリティ
JapaneseChronology 和暦

現在時刻エポック値の表現と取得方法

数値 System.currentTimeMillis()やSystem.nanoTime()
Instant Instant.now()

実装方針

時刻の扱い

  • データベース上はエポック値を格納(JDBCではjava.sql.Dateを経由。ミリ秒以下が欲しければjava.sql.Timestamp経由)
  • コード上はjava.time.ZonedDataTimeで扱う。ただしUTC日時とローカル日時の区別は開発者の責任

時間の扱い

  • データベース上は数値として格納(JDBCではintを経由)
  • コード上はjava.time.Durationもしくは数値で扱う

ラベル日の扱い

  • データベース上は数値(20140101のような数値)として格納(JDBCではStringもしくはintを経由。タイムゾーン非依存にするため)
  • コード上はjava.time.LocalDateで扱う

JDBCまわりの対応は未整備です。java.sql.ResultSetもjava.sql.PreparedStatementもDate/Time APIにまだ対応していません。Object型でカラム値を読み書きするメソッドは追加されていますが、気持ち悪い上に動くのか不明(JDBCドライバ次第)なので、現状は旧来のjava.util.Dateを経由して変換する必要がありそうです。

以下にサンプルコードを載せます。コメントの想定例を見ながら読んでください。

import java.util.*;
import java.time.*;
import java.time.temporal.*;
import java.time.chrono.*;
import java.time.format.*;

public class Time {
    public static void main(String... args) {
        // 共有コンテキスト(毎回作る必要はないので、アプリグローバルでもよい)
        ZoneId jst = ZoneId.of("JST", ZoneId.SHORT_IDS);
        //        ZoneId jst = ZoneId.systemDefault(); // 手元コードならこれでもOK
        ZoneId est = ZoneId.of("EST", ZoneId.SHORT_IDS);

        Locale jpLocale = new Locale("ja", "JP", "JP");
        Chronology wareki = Chronology.ofLocale(jpLocale);
        //        Chronology wareki = Chronology.of("Japanese"); // 上記2行の代替例


        // 入力数値からZonedDateTime(内部時刻)
        // 想定例: 利用者は日本タイムゾーンで日時を入力 
        ZonedDateTime myTime = ZonedDateTime.of(2014, 1, 31, 10/*hour*/, 0/*min*/, 0/*sec*/, 0/*nanosec*/, jst);
        System.out.println(myTime);

        // ZonedDateTime(内部時刻)から表示
        // 想定例: 利用者は日本タイムゾーンでの日時表示を期待
        System.out.format("%d, %d, %d\n", myTime.getYear(), myTime.getMonthValue(), myTime.getDayOfMonth());

        // ZonedDateTimeを使う日付計算
        // 単純な計算はplusMonthsやminusMonthsなどのメソッドを使う
        // 少し複雑な計算はTemporalAdjustersを使う
        // 例: 2014.1.31の1ヶ月後の最初の土曜日は? => 2014.3.1
        ZonedDateTime deadline = myTime.plusMonths(1).with(TemporalAdjusters.next(DayOfWeek.SATURDAY));

        // 時刻の比較
        // 例: 締切り前かの判定など
        if (myTime.compareTo(deadline) < 0) {
            System.out.println("before deadline");
        }

        // 日数計算
        // 例: 締切りまで残り何日か?
        // 注意: 締切り日の仕様を明確にするのはコード以前の話(たとえば、1月1日締切りの意味は、当日0時なのか夜11:59つまり事実上翌日の0時なのか)
        Duration duration = Duration.between(myTime, deadline);
        System.out.format("%d days until deadline\n", duration.toDays());
        
        // JST時刻からEST時刻に変換(Instantとしては同時刻)
        // 想定例: 日本のカレンダーで作った予定を米国のカレンダーで表示
        ZonedDateTime ustime = myTime.withZoneSameInstant(est);
        System.out.println("US: " + ustime);

        // ZonedDateTime(内部時刻)から和暦出力
        // 想定例: 利用者が和暦での日時表示を期待
        ChronoLocalDate heisei = wareki.date(myTime);
        // "Heisei"=>"平成"の文字列変換は自前実装が必要
        System.out.format("%s, %d, %d, %d\n", heisei.getEra(), heisei.get(ChronoField.YEAR_OF_ERA), heisei.get(ChronoField.MONTH_OF_YEAR), heisei.get(ChronoField.DAY_OF_MONTH));
        
        // 和暦年号(H26)から西暦年号(2014年)へ変換
        // 想定例: 利用者が和暦で日時を入力 
        String WAREKI_HEISEI = "Heisei"; // "Heisei"はハードコード
        JapaneseEra jpEra = JapaneseEra.valueOf(WAREKI_HEISEI);
        ChronoLocalDate heisei2 = wareki.date(jpEra, 26, 3, 15);
        System.out.println("A.D. " + heisei2.get(ChronoField.YEAR)); //=> 2014

        // ラベル日
        // 想定例: クリスマスの終日予定は、どのタイムゾーンのカレンダーで見てもずれない
        LocalDate xmasDay = LocalDate.of(2014, 12, 25);
        
        // 旧API(java.util.Date)との変換
        // java.util.Date => Date/Time API
        Date now = new Date();
        ZonedDateTime ztime = ZonedDateTime.ofInstant(now.toInstant(), jst);

        // Date/Time API => java.util.Date
        ZonedDateTime znow = ZonedDateTime.now();
        Date dateNow = Date.from(Instant.from(znow));
    }
}

関連文書:

  • 関連文書は見つからんがな

Posted by & filed under いろいろ.

このエントリーを含むはてなブックマークはてなブックマーク - Go始めてました このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - Go始めてました Share on Tumblr Digg This

アリエルってJavaの会社だよね。でもね、Javaだけの会社じゃないんだよ。大部分のコードはJavaで書かれているのは事実だけど、それだけじゃないんだよ。ツールとか製品の周辺部分はRubyだったり、Pythonだったりするんだよ。まだ、一部Perlが残っているんだけど、Perlはだんだん駆逐されていっているんだよ。テスト関係のコードは、とってもRubyで書かれているんだよ。

昔からあるプロダクトはJavaなんだけど、新し目の製品は実はJavaじゃないんだよ。Goなんだよ。なんでGoにしたのかは、

  1. 1.1がでて、安定していそうだから
  2. コンパイルが速いのでコードを書いてデバッグするまでのサイクルが短くできるから
  3. それでいて実行速度が速いから
  4. 最低限必要そうなライブラリは揃っているから
  5. 文法的なところとか、その割り切りが、一部の人にフィットしたから
  6. マイナー路線
  7. 並列性とか、なんとか

無理やり7つも上げてみたよ。でも、横から聞いていると、大谷さんが「Javaは飽きたので、Go好きだから製品で使ってみたいからGoにして!」って言っていたような…。結局、好き嫌いで決まっちゃったみたいだよ。

 

面白そうだからという理由だけでGoで始めちゃったので、Goを書きたい人は来てね。


関連文書:

  • 関連文書は見つからんがな

Posted by & filed under いろいろ.

このエントリーを含むはてなブックマークはてなブックマーク - Server-Sent Eventsのエスケープ このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - Server-Sent Eventsのエスケープ Share on Tumblr Digg This

Server-Sent Eventsを使うとサーバーからクライアントにデータをPUSHすることができます。使い方はこの辺を参考にしてください。

node.js + expressでサーバー側を実装するとこんな感じになると思います。

app.get('/event', function(req, res) {
  res.type('text/event-stream');
  res.write('data: ' + data + '\n\n');
});

この+ data +部分、data変数が任意の文字列の場合簡単にインジェクションができてしまいます。では安全にdata変数を出力するにはどうすればいいかを考えてみました。

改行をなんとかする

CRLFがterminatorなのでdata変数に改行があると当然おかしくなります。

対応方法として、生文字列を渡したいのであればssl.jsのようにCRLFでsplitしてdataフィールドを複数書けばよいでしょう。またJavaScriptの場合文字列をvalidなJSONとして扱えるため、とりあえずJSONにする手も使えます。(ECMA-262JSONText -> JSONValue -> JSONStringRFC 4627の場合はobjectとarrayのみJSON-text = object / array

HTMLタグをなんとかする

Server-Sent EventsのContent-Typeはtext/event-streamなので、このURLをまともなブラウザで直接表示した場合ファイルダウンロードになるなど、少なくともHTMLとして開かれることはありません。しかし以前からはせがわようすけさんらが警鐘を鳴らしているIEのContent-Type無視によってHTMLとして開かれることがあります。

例えば以下のようなサーバーにIE7で/event/a.htmlを開くとalertが表示されました。

app.get('/event/:id', function(req, res) {
  res.type('text/event-stream');
  setInterval(function() {
   // 任意の文字列を返している、という想定
   res.write('data: <script>alert(1)</script>\n\n');
  }, 1000);
});

IE8以降であればnosniffでHTMLへの昇格を防げますが、IE7以下の対策をするとしたらJSONにした上で「/」「<」「>」「+」をエスケープするくらいでしょうか。XMLHttpRequestであれば独自のリクエストヘッダをつけたりPOSTで投げたりといった方法もありますが、EventSourceはURLの指定くらいしかできないので使えません。あとscriptタグで読み込んだときにどうなるんでしょう?JSONにしてあれば大した問題にはならなそうですが。

まあServer-Sent Events使うようなサイトをIE7で見るやつなんていねーよ、って言われたらそれまでですが。

検証スクリプト


関連文書:

  • 関連文書は見つからんがな

Posted by & filed under いろいろ.

このエントリーを含むはてなブックマークはてなブックマーク - @ITにインタビュー記事が載りました このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - @ITにインタビュー記事が載りました Share on Tumblr Digg This

採用のためのインタビュー記事が@ITに載りました。

兼務しているワークスアプリケーションズのゲストフェローの立場でインタビューを受けましたが、アリエルとしても通用する内容のつもりです。

タイトルの「エンタープライズ領域こそ面白い」は少し過剰な表現で、真意は「エンタープライズ領域も面白い」です。

記事のために敢えて極端に振った表現をしました。エンタープライズという用語が、つまらないものだと思われすぎている気がするからです。実際のところ、サービスが企業向けだろうと一般ユーザ向けだろうと、基盤となる部分できちんと技術的なことができる職場であれば、どちらも同じぐらいに面白く、どちらも同じぐらい良い経験が積めると思います。作った技術の上で提供されるサービスが誰を向いているかは、単純に人それぞれの嗜好や価値観であって、その時々の直感で選べばよいかと思います。

むしろ技術者の経験として大きな違いを生むのは、コードを書き捨てる職場か、コードを資産として残す職場かの違いだと思います。

コードを書き捨てる環境では、抽象層を積み上げるという感覚がなかなか育ちません。この感覚がないと、コードをたくさん書いても、単に誰かの作った抽象層の上で何かした経験、もっと具体的に言うとAPIを覚えて組み合わせで何かする経験が増えるだけしかできません。技術者の初期のキャリアでは意味がありますが、これだけしか経験していないと辛いと思います。もっとも、こういう職場であっても、新しい言語や新しいフレームワークを試す土壌があるなら、筋の良い人は、多くの利用経験から類似性を見つけて抽象化できます。自分なりにオープンソースなどで同じ経験を積んでもいいでしょう。

最悪パターンは、コードを書き捨てる環境で、かつ言語もフレームワークも固定化された環境です。頭の良い人はバッドノウハウの権威になって職場で重宝されます。使っている技術がメインストリームである間は、転職にも苦労しません。しかし、ある技術がメインストリームである期間は誰にも読めません。技術者にとってリスクが高いキャリアの積み方です。


関連文書:

  • 関連文書は見つからんがな

Posted by & filed under いろいろ.

このエントリーを含むはてなブックマークはてなブックマーク - 川野さんの退社風景 このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - 川野さんの退社風景 Share on Tumblr Digg This

川野さんがアリエルをさりました。まあ、彼がどこで何をしようがいいですが、昨日は川野さんの最終出社日。無事、みんなの投票で決まったプレゼント『アジャストパワーウエイトベスト10KG、通称、防弾チョッキ』を渡すことができました。川野さんも喜んでくれたようです。

 

プレゼントを開け、早速着替えてみた川野さん

Photo 2013-11-05 15 23 46

 

そのままトレーニングを始める川野さん

Photo 2013-11-05 15 24 07Photo 2013-11-05 15 24 47

 

ひとしきりトレーニングに励んだ後、川野さんからもプレゼントがありました。まさかりを片手にお菓子を渡そうとするも、怖がられてしまい渡せない川野さん。最終的にとまるんるんに切りかかっていました。

 

感情を爆発させる川野さん

Photo 2013-11-05 15 34 19

 

おまけ

image

 


関連文書:

  • 関連文書は見つからんがな

Posted by & filed under .

このエントリーを含むはてなブックマークはてなブックマーク - Software Design 2013年11月号のEmacs特集にコラムを寄稿しました このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - Software Design 2013年11月号のEmacs特集にコラムを寄稿しました Share on Tumblr Digg This

Software Design 2013年11月号のEmacs特集が、業界で話題沸騰です。

わずか1ページのコラムですが寄稿しました。

目次は技術評論社のサイトで見られます。

執筆の時間が取れなかったのでコラムでお茶を濁しました。とは言え、今の日本で、Emacs特集にアリエルの寄稿がないと雑誌の売上に影響を与えかねません。なので、社内の若きエース高石さんに記事を書いてもらいました。

まだ献本にまともに目を通していません。雑誌には執筆者全員の.emacs.elの行数が載っているはずです。正直に.emacs.elの行数を申告しましたが、もしかしたら自分が最短行数かもしれません。長ければいいってものではないですが、ひとりだけ極端に短かったら少々恥ずかしいですね。


関連文書:

  • 関連文書は見つからんがな