SE215 Special Editionを買いました

2年ほど前に買ったATH-CKS90が断線してしまったため、イヤホンを新調しました。 中学の頃にMDプレイヤーを使うようになってから今まで、イヤホン・ヘッドフォンはすべて断線してダメにしているので、「今回は断線しにくそう・断線してもケーブル交換できる」という基準で選んでSE215 Special Editionになりました。 音質に関しては、自分は信仰心が低いのとアイフォーンに直接挿してるのでなんとも言えませんが、遮音性が高く阿澄佳奈の声がクリアに聞こえるような気がします。+7000円程度でスペック上では高音を更にカバーしてるSE315が射程に入るので、お金に余裕がある人はそちらをおすすめします。

オーディオは一線を超えると感性工学とプラセボによる物だと私は考えてるので、沼に落ちないように気をつけます。

【国内正規品】 SHURE 高遮音性イヤホン ブラック SE315-K-J

【国内正規品】 SHURE 高遮音性イヤホン ブラック SE315-K-J

最後に、2年間もありがとうATH-CKS90

node.jsでTwitter UserStreamを取得する

またUserStreamか・・・、ブログ再開するたびにUserStream書いてる気がする。 node.jsの非同期処理はUserStreamと相性が非常にいいのに情報が古かったりするので書きました。 取りあえず動くのをgithubにおいてます。

oauthモジュールのgetメソッドにコールバック関数を渡さないとストリームを返すので便利です。

var req = oa.get(endpoint, config.access_token, config.access_secret);
req.on('data', function(chunk) {
  console.log(chunk);
});

ただし、chunkは適切な場所で分割されているとは限らないので、そのままJSON.parse(chunk)すると死にます。改行コードを探して1行ずつパースする必要があります。 bylineというモジュールが便利です。

はてなブログProにした

独自ドメインとmarkdown記法とSyntax Highlightを使いたかったので選択肢あまりなかったのと、 金払えばブログ続けるだろうと思ったので、はてなブログをProにしてみました。

私の980はてなポイントがまわりまわって、いつも便利情報を提供してくれているひとでさんの血肉になることを祈っています。

mongooseの使い方まとめ

随時更新予定

目次


クエリ


動的query

  • ToDo

whereexec

var query;
if(screen_name) {
  query = query.where({ screen_name: screen_name });
} else if(user_id) {
  query = query.where({ user_id: user_id });
}
query.exec(function(err, data) {
  console.log(data);
});

要素数のカウント

query.countで要素数をカウントできる.limitとskipは無視される.

query.find(function(err, count) {
  console.log(count);
});

_id


uniqueで配列じゃなければなんでも使える

var User = new Schema({ _id: Number, screen_name: String });

埋め込みオブジェクトも使える

var Good = new Schema({ _id: { from: Number, to: Number }});

_idを明示的に定義しなかったら,ObjectIdという12byteの型で定義される. ObjectIdには4byteのタイムスタンプが含まれるのでcreated_atを定義する必要は無い.

var Id = new Schema({ text: String });
mongoose.model('Id', Id);
Id = mongoose.model('Id');
var id = new Id({ text: 'hoge' });
console.log(id._id);
console.log(id._id.getTimestamp());

結果

5073865056f6147bb1000001
Tue Oct 09 2012 11:05:04 GMT+0900 (JST)

node.js+MongoDBでtwitter apiを使うときに注意すること

こちらになんの変哲もないjsonがあります.

{"id":255113756093329409,"id_str":"255113756093329409"}

これをJSON.parseすると

{ id: 255113756093329400,  id_str: '255113756093329409' }

お分かりいただけるだろうか?不思議な力によりidの下1桁が9から0になってしまった. このidは先程自分が腹減ったとTwitterでつぶやいたもののstatus idなので最近のつぶやきを扱うには何らかの対策が必要である.

対策1: id_strを使う

Twitter APIは64bit整数が扱えない残念な言語の為にidとつくフィールド全てにid_strというidを文字列にしただけのフィールドを持っている. なのでよっぽどのことがない限りこちらを使えばよい.

対策2: MongoDBのNumberLongを使う

MongoDBではNumberLong('255113756093329409')と書けば64bit整数が扱える. sortしたい,コレクションが大量にあるのでidに20Byteも使うのは勿体無い等の場合こちらを使えばいいだろう.

みんなのアイドルmongooseでNumberLongを使いたい時は,mongoose-longというモジュールがある.

const mongoose = require('mongoose');
require('mongoose-long')(mongoose);
const Schema = mongoose.Schema;
var Status = new Schema({ id: Schema.Types.Long });
mongoose.model('Status', Status);
Status = mongoose.model('Status');
var status = new Status({ id: '255113756093329409' }); // Stringで渡す
console.log(status.id);
console.log(status.id.toString(10));

結果

{ _bsontype: 'Long', low_: 155332609, high_: 59398300 }
255113756093329409

しかしこのmongoose-longは不完全で検索,更新ができなかったりするので,mongooseのlib/schema/number.jsあたりとmongoose-longのlib/index.jsを参考にcastForQuery関数を追加したりする必要がある.

Expressの5行でできるCSRF対策

特殊なウィルス怖いですね.今後CSRF対策してないフォームを公開したらウイルス作成罪で逮捕されるかもしれません. NodeのWEBフレームワークExpress(が使ってるミドルウェアフレームワークのConnect)では数行追加するだけで,セッション毎の固定トークン方式でCSRF対策ができるので紹介する.

ソース デモ

基本的にはapp.use(express.session());app.use(app.router);の間に2つミドルウェアを追加し,ビューのformに隠し項目でトークンを追加するだけである.

// app.js
...
  app.use(express.session());
  app.use(express.csrf()); // 追加
  app.use(function(req, res, next) { // 追加
    res.locals._csrf = req.session._csrf;
    next();
  });
  app.use(app.router);
...

app.use(express.csrf());の部分はconnectのmiddleware/csrf.js参照. req.session._csrfにトークンが追加され,POSTメソッド等でtokenが一致してるかチェックされるようになる. res.locals._csrf = req.session._csrf;で_csrfをビューから参照できるようにしている.

後はビューのフォームにトークンを追加する.

// index.jade
...
  form(method='post')
    legend= 'CSRF対策済みフォーム'
    input(type='text', name='text')
    input(type='hidden', name='_csrf', value=_csrf) // 追加
    input(type='submit')
...