Perl の Locale::Maketext::Lexicon::Gettext は以下のような Gettext ライクなフォーマットを扱うが、同じようなことを JS でしたいとき

%1 さん、こんにちは
%quant(%1,user,users)
  • %function() は任意の関数が呼べる感じなので、JS でもそのようにしておく。
  • numf は実装してない。
  • Locale.data= { ... } みたいなのが言語別に完全にわかれているのを想定してる
var Locale = {
    loc : function (msgid, arg) {
        var args = Array.prototype.slice.call(arguments, 0);
        var text = Locale.data[msgid];
        if (text) {
            if (/%/.test(text)) {
                text = text.replace(/%(\d)/g, function (_, n) {
                    return args[n];
                });
                text = text.replace(/%([a-z*#]+)\(([^\)]+)\)/g, function (_, func, args) {
                    if (func == '#') func = 'numf';
                    if (func == '*') func = 'quant';
                    args = args.split(/,/);
                    return Locale[func].apply(null, args);
                });
                return text;
            } else {
                return text;
            }
        } else {
            return msgid;
        }
    },

    quant : function (number, singular, plural, negative) {
        if (number == 0 && negative) { // no warnings
            return negative;
        } else
        if (number == 1) {
            return singular;
        } else
        if (plural) {
            return plural;
        } else {
            return singular + 's';
        }
    },

    numf : function (number) {
        return number; // XXX
    }
};
  1. トップ
  2. tech
  3. Perl の Locale::Maketext::Lexicon::Gettext フォーマットのメッセージをJSでフォーマットする

一昨日、15時ぐらいまでは普通だったが16時ごろから急激に悪寒、歯がガタガタしてどうしようもなく、18時ごろに会社を出た。電車に乗るうちに悪寒から吐き気になって途中下車。トイレに行って吐こうとしてみたが吐けず、とりあえず売店で買い物してビニール袋を用意しつつなんとか帰宅した。帰宅してからは吐き気よりもとにかく頭痛がひどくなった。帰宅した時点で体温は38℃前後だった。

仕事で対応が必要だったのでしかたなく VPN 繋いで居間で半分寝ながら1時間ぐらいごとに対応していたが、こっちで対応が必要になるタイミングがさっぱりわからずイライラした。おかげで悪夢倍増しつつだらだら夜中まで対応するハメになった。その日は結局居間で寝たが尻が痛くなった。

日があけて9時近くになったので病院に行って診察をうけたが今一原因はわからなかった。インフルエンザではなかった。鼻も喉もおかしくなく、下痢もないので、薬はロキソニンの処方だけだった。

とりあえず勤怠で休みますというメールをしたが、あいかわらず仕事でタイミング不明の対応が必要だったので1時間ぐらいごとにチェックして対応していた。

午後からは熱が下がった。たぶん仕事でイライラしすぎたせいで熱出たんだと思う。仕事ほんとしたくない。

  1. トップ
  2. 体調不良
  3. 1回休み

洗濯槽クリーナー N-W1 -

4.0 / 5.0

そろそろ、1年ほど使っているので洗濯漕綺麗にしとかないとなあと思っていた。とりあえず手元にあったワイドマジックリンでやってみたが、落ちてんのか落ちてないのかよくわからない感じだった。

いろいろ商品があるけど、やっぱ純正で一度やってみようと思いやってみた。入れて1時間ぐらい動かしたあと、一旦止めて見るとかなり濁っていて (ワイドマジックリンやった直後でも)、さすがに強力という印象。

1500円〜2000円で1回分と、値段がかなり高く感じる。たぶん防錆剤とか入れて調整してるのかな。アマゾンへのリンクを貼ったけどヨドバシが最安だった。落ちている感じはするので、来年もたぶんこれでやると思う。

アース製薬 ブラックキャップ 12個入り -

5.0 / 5.0

去年夏ごろに出てから家の中の各所に設置していた。ネットで検索すると圧倒的に人気がある商品。

一応設置してからは一度も見ていないけど、見ていないので効いているのか効いていないのかはよくわからない。今年ずっと見なければ効いてると考えてよさそう。

半年で誘引効果が切れるらしいので、再度購入して全部とりかえた。そんなに高くなく、12個入っていて、半年効くというのが良い。

桜の季節はいいんだけど、こういう細かい写真はやはり JPEG の圧縮ノイズが非常に気になる。Lightroom で見てるうちは綺麗なのに、JPEG として出力すると、たとえクオリティを100%に設定しても圧縮ノイズがでて悲しくなる。

せっかく Retina になって細かい画像も出せるようになったのに、ブラウザがクソフォーマットにしか対応していないのでどうしようもない。

次世代 JPEG と呼ばれるものは、以下のようにあって、それぞれのブラウザでそれぞれに使えるのがあるが、全部のブラウザで使えるというものはない。政治的なものが絡んでいて大変クソっぽい。画質とか気にする人が全然いないから対応が全くすすまないんだと思う。

  • JPEG 2000
    • Safari が対応
    • Mozilla はWONTFIX(笑)
    • 圧縮スピードが遅いとかなんとか言われてる
  • JPEG XR
    • IE が対応
    • Mozilal は無視
    • リファレンス実装がクソとかなんとか言われてる
  • WebP
    • Chrome, Opera, Android とかが対応
    • Mozilla は 未対応
    • 権利的にどうなの?とか言われてる

全部のフォーマットに対応する ImageMagick のビルドを試みたがうまくいかなかった。

WebAudio で ScriptProcessorNode とかを使ってちょっと変なことしようと思うと、波形が実際どうなっているのか見たくなったりするわけですが、うまいこと取得できなくてイライラするわけです。なのでトリガをかけて一定期間の波形を表示するのを作りました。

デバッグ用なので、UI 上には殆ど機能はなく、以下のようにコード上で設定を引数で渡す感じです。トリガはSimple, RaisingEdge, FallingEdge, DualEdge だけとりあえず実装してあります。実装すればチャンネル間の and トリガとかもできる感じの設計です。

WebAudioDebug.prove(context, merger, {
    bufferSize : 64e3,
    windowTime : 100e-3,
    highResolution : false,
    trigger : WebAudioDebug.OscilloscopeNode.Trigger.RaisingEdge({ triggerChannel: 0, width : 10, threshold : 0.5 }),
    continuous : false
});

作ってる途中でやる気が失せたので、特に highResolution: true (Retina 対応) にしたときパフォーマンスがめっちゃ劣化するけどそのままです。あと、繋げる段数が違ったノードを merge して渡すとズレたりするので、ちょっとめんどうくさい感じです。なんとかしたいけど、その前にやる気がなくなったのでそのうちやる気がでたらやるかもしれないです。

  1. トップ
  2. tech
  3. WebAudio のデバッグ用のオシロスコープ

ngResource は $get してオブジェクトを変更して \$save を呼んだらサーバサイドに反映とかいうことができます。

  1. データを $get などで取得した直後の状態、(サーバサイドで) 保存されている状態
  2. 取得したリソースを変更した状態、(サーバサイドで) 未保存の状態
  3. $save などで保存完了した状態、(サーバサイドで) 保存されている状態

とリソースの状態が変化します。

しかし、実際のアプリケーションでは、変更されたが更新されていない状態というのを表示したくなることが多々あります (変更があって未保存なら項目の色を変えるとか)。

なので、保存前の状態をどこかに保存して、保存されたらそれを更新するとかいう作業が必要になります。ただ、コントローラ側の ngResource のコールバックでいちいちこんなことしようとするとバグるので、ngResource の定義側でなんとかしたいところです。

transformResponse を使う

transformResponse は ngResource で何かしたときに呼ばれてくれるので、ここで angular.copy() で resource.saved みたいなプロパティに変更前のデータを全部つっこんでやると大変楽です。だいたい以下のようなコードです (実際はコードをまとめるけど)。

var Entry = $resource('/api/entries', { id : '@id' }, {
    'query':  {
        method:'GET',
        isArray: true,
        transformResponse : function (data, headers) {
            data = angular.fromJson(data);
            data.saved = angular.copy(data);
            return data;
        }
    },
    'save':  {
        method:'POST',
        transformResponse : function (data, headers) {
            data = angular.fromJson(data);
            data.saved = angular.copy(data);
            return data;
        }
    }
});
// controller
$scope.entry = Entry.get({ id : 1 });
// $scope.entry.saved is original data
// template
<div ng-class="{ changed: entry.body != entry.saved.body }">
    <textarea ng-model="entry.body"></textarea>
</div>

このように、取得したリソースを $scope に突っ込み、リソースを対象に ng-model を設定してやると、あとはいい感じになります。save などを呼ぶと変更された内容でリクエストが飛び (unsaved も送信されるのが余計ですが)、サーバ側で適切に保存されたエントリのレスポンスを返せば、transformResponse でリソースの更新がかかるので、全状態が自動でリセットされます。

  1. トップ
  2. tech
  3. ngResource を使って未保存の情報を明確にする