Google アナリティクスの利用規約と、クッキーとリファラの話の続き

の続き。

長い、意味がわからない、FUDだ、クッキー関係ない、といった批判を受けて、補足と整理をします。

Google アナリティクスの利用規約

Google アナリティクスについて、知らなかった点を補足。

  • 前の記事に書いたようなことをすると、Google アナリティクスの利用規約違反と見なされる可能性がある。
  • カスタム変数を使わずに、ビジターIDを Google アナリティクスの画面から検索・取得することはできない。

利用規約の「7. プライバシー」で、個人情報をGAに格納したり関連づけたりする行為が、禁止されている。

7.  プライバシー  お客様は、本サービスを利用する(又は第三者が利用する)にあたって、個人を特定するデータ(氏名、Eメールアドレス、請求関係の情報等の個人情報)又はGoogleが当該情報に合理的に関連付けることが可能なその他のデータの追跡、収集又は格納をしないものとします(かつ第三者にこれらをさせないものとします)。お客様は、適正なプライバシー・ポリシーを策定してこれを固守し、訪問者からの情報の収集に関して適用される法令を全て遵守することとします。お客様はプライバシー・ポリシーを掲載しなければならず、当該プライバシー・ポリシーにはお客様が、トラフィックデータの収集のために cookie を使用していることが示されなければならず、お客様は、本サービスの一部であるプライバシー機能(例えば、オプトアウトの機能)を回避してはなりません。

以下のような使い方は規約違反なんじゃないかと思うのだが、

一方、ビジターIDは「個人を特定するデータ(氏名、Eメールアドレス、請求関係の情報等の個人情報)」に当たらない、と言ってる人たちもいる。

Track The Visitor ID

Google Analytics doesn’t let you put in personally identifiable information, but it’s generally held that random visitor id’s that you can then compare with your own database outside of GA, are ok. so this way you can track the same visitor even when they’re not logged into your site.

_gaq.push(['_setCustomVar',1,'UserID','1234567890',1]);

20 Ways to Use Google Analytics Custom Variables

↑ランダムなビジターIDをカスタム変数にセットすることで、サイトにログインしていなくても行動をトラッキングできる。

It’s a fairly common practice now, and as long as your visitor ID isn’t their social security number or their name or something, as long as it’s a random string of numbers that you have also stored within your own system, most experts read that as acceptable.

:

I really think it’s barely a gray area. In the 50 Shades of Gray regarding storing PII in GA, this is Hex #eeeeee imho.

20 Ways to Use Google Analytics Custom Variables

↑ たいていのエキスパートは許容範囲だと読んでいる。GA に PII(個人識別可能情報) を保存するグレーゾーンの中でも、一番白に近いやり方だ。

別の記事。

For the sake of this example I’m going to use a little piece of JavaScript to create a unique ID for visitors. I’m actually going to extract a unique ID from the Google Analytics __utma cookie. Then I’m going to set the unique ID in a custom variable, specifically in Custom Variable slot 5.


var a = _uGC(document.cookie, '__utma', ';');
var id = a.split(".");
_gaq.push(['_setCustomVar', 5, 'VisitorID',id[1],1]);

Merging Google Analytics with your Data Warehouse - Analytics Talk

↑ ビジターにユニークID をふるため __utma の2番目の値(ランダム値)をカスタム変数のスロット5番に設定する。 (3個目も足した方が確実では)

@Tim: Spot on, 100% correct. I know Section 7 very well :) But I believe that this type of integration is a completely valid method that lives in a grey area. I believe that the TOS is out of date with the current ecommerce tracking code. But in the end it’s up to every organization to evaluate their needs and ho to meet them.

Merging Google Analytics with your Data Warehouse - Analytics Talk

↑ セクション7はよく知ってる:)けどこれはグレーゾーンの中で完全に妥当な手法だ。

というわけで、自分には黒っぽく見えたけど、やってる人は沢山いそうだし、黙認されている可能性もあるかもしれない(実際どうなのかは知りません)。

トラッキング用のクッキー、ID入りリファラソーシャルブックマーク、URLリコメンド の関係について

図を描こうかと思ったけど、別にいいか。

  • リファラにユーザIDが含まれていると、トラッキング用のクッキーとリファラのユーザIDを組にして保存することができる。 (技術的に可能)
  • マイホットエントリーや Gunosy のような、URLリコメンデーションの仕組みは、そこから毎日様々なサイトにアクセスさせることを目的としている。 (事実)
    • URL にユーザIDが含まれている場合、リファラによってユーザIDが各サイトに日常的に送信されることになる。 (事実)
  • パーソナライズされたページは、パーソナライズされているので、本人が見ている可能性が高い。 (事実)
  • ソーシャルブックマークには、そのユーザの関心事が記録されているので、マーケティング上の価値があるのではないか。 (想像)
  • リファラで送信されたユーザIDと、アクセス先のサイトでのログインIDを関連づけることができる。 (技術的に可能)
    • ポイントカードの類では、買い物の履歴や、住所氏名年齢職業電話番号と関連付けることができる。 (技術的に可能)

これをリスクととるのか、どのくらい許容できるのかは、個人によって違うだろうと思う。

前の記事にも書いたとおり、わざわざ直すにはコストが大きすぎるような気がするが (想像)、自分はクッキーがたくさん残ってるのを見て、嫌だなーと思った (事実)。



はてなIDがクッキーで約50サイトに送られていた話

(追記) 要点を整理をした記事を書きました。こっちのほうが、余計なこと書いてない分、わかりやすいかもしれません。

はてなブックマークに、マイホットエントリーという大変すばらしい機能があって、毎日見ている。

自分のマイホットエントリーのURLはこう。

マイホットエントリーを見ていると、はてなID koseki を含むリファラが各サイトに送信される。

リファラGoogle アナリティクスの __utmz に記録される。

Firefox には、全クッキーの値を横断検索する機能がある。

設定プライバシーCookieを個別に削除検索

自分の環境では、およそ50個*1のクッキーに koseki という文字列が含まれていた。

f:id:koseki2:20130509143452p:plain

あんなサイトやこんなサイトを、本名を名乗って閲覧していたのか、と戦慄した。

はてなIDGoogle アナリティクス

戦慄したため、うすぼんやりとしか理解していなかった Google アナリティクスのクッキーについて、ちまなこで調べた。

流入元を記録するクッキー __utmz の有効期限は6ヶ月。__utmzリファラで書き換わる。

それとは別に、ビジターを識別する __utma というクッキーがある。有効期限は最後にアクセスしてから2年。

リファラが送られた時点で __utma を、はてなIDと関連づけることが可能になる。

するとどうなるか

ビジターを識別する以外に意味を持たない __utma は、はてなIDと置き換えられ、最新の興味関心(=はてブ)を、アクセス先のサイトに延々と提供し続けることになる。

本人?

はてブのページからアクセスしているのは本人とは限らない。が、

を見ている者が、自分以外にいるとは思えない。自分のはてブトップが Google でヒットしているのを見たこともない。

アクセス回数から、どの __utma が本人なのか推測できる。

本人がブックマークしていない URL へのアクセスは、マイホットエントリー経由なので、本人だと確定できる。

プライベートモードの場合も本人と確定できるが、そのユーザの関心事を調べることはできない。クロスドメインのIDとしてのみ機能する。

ID連携

たとえば TSUTAYA のサイトでも、もちろん GA でトラッキングが行われている。

マイホットエントリ経由で TSUTAYA の映画レビューにアクセスし、レンタルするためにログインする。

と、はてなIDとTポイントカードが連携してしまう。

GigazineB級グルメ記事をブックマークして、ファミマでその商品を買った、とか、ネットの外までトラッキングできるようになる。

個人情報の積み増し

自分のところには、いつ登録したのか覚えていない「Tアンケートメール」というのが大量に送られてくる。

From: Tアンケートメール
日付: 2013年4月26日 10:09
件名: 答えてお得なQ&Aメール【5問で5ポイント(PR)】

★たった5つの質問に答えるだけで、★
★5ポイントがもらえる      ★
(2013/4/26)

いつもTサイトをご利用いただき、ありがとうございます。

このメールは、「Tアンケートメール」にご登録いただいているみなさまに、
Q&A形式でお得な情報をお届けします。
回答するだけでポイントがもらえますので、是非ご参加ください!

◆「映像レンタル・動画配信に関するQ&A!」

◆回答期限 2013/5/10(金)まで

◆特典  Tポイントを5ポイント

・回答いただいた内容は、カルチュア・コンビニエンス・クラブ株式会社が、
T会員規約に従い責任を持って管理し、お客様の情報として利用致します。

  本アンケートをご案内するメールが届いたご本人様のみが、
  本アンケートの依頼対象となられた方です。
  依頼対象となられたご本人様以外は、大変恐縮ですが
  回答をご遠慮ください。

ちなみに 3月、4月に送られてきたテーマは、

  • 保険に関するQ&A!
  • メンズエステに関するQ&A!
  • 自動車に関するQ&A!
  • 貯蓄に関するQ&A!
  • 自動車保険に関するQ&A!
  • 資産運用に関するQ&A!

だった。具体的に何をやっているのかは知らないが、なんとなく、Yahoo 知恵袋の怖い質問シリーズを連想してしまう。

IDの先にいる生身の人間の性質を、法に触れない範囲で可能な限り収集したい、という欲求があるとしたら、ソーシャルブックマークのユーザIDは格好のターゲットになり得る。

Gunosy

最近話題の Gunosy の URL も、はてブと基本同じだった。

といったURLで、パーソナライズされたURL集を配信しており、各サイトにリファラが送られている。

Facebook の例

ここまで書いてから Facebook の ID がリファラで漏れる mala さんの記事を見つけてしまった。

なんか 100% 蛇足だった気がしてきたが、Facebookはてブでは違うところもある(と思う)。

  • Facebook の広告を毎日何件もクリックしたりしないが、マイホットエントリーは毎日何度もクリックする(人もいるかもしれない)
  • Facebook では他人事だった話が、はてブだとリアルに思える(人がいるかもしれない)

アンチパターン

本人が見ている可能性が高いページから外のサイトに出るときは、リファラにユーザIDを含めない方がよい。

代替案

デメリットが大きすぎて、あんまり現実的でないような気もする。が、一方で、名前が載ったクッキーが50個も見つかるのも、けっこう本気でいやだ。

アドオンでリファラをオフにしたりはしたくない。GA をオプトアウトする、という選択肢もあるけれども、

根本的な解決にならない。


線を引く

自分のプライバシーをどこまで公開できて、どこから守りたいのか、自分でもよくわからない。何もかも秘密にしたい日もあれば、全裸で外に出たい日もある(ない)。

どこに線を引くかの基準には、市場の側面と倫理の側面があるように思う。

市場の話

俺のプライバシーと交換で、もっといいサービスを受けるため、お前らも安く売んな、というのが市場の話。

われわれがオンラインで何か活動をすれば、必ず誰かがそれをデータベースに記録し、その情報に基づいて何かを売りつけようとしてくる。これについて はオンラインで活動しないという選択肢を除いてわれわれができることはほとんどない。それに赤ん坊がいる家庭にオムツの広告が表示されたり、車を買い換え ようと思っているときに車の広告が表示されたら便利なことだってある。いずれにしてもささいなことだ。

Wall Street JournalがFacebookのプライバシー問題をめぐってから騒ぎ - TechCrunch

IT業界の人が「ささいなことだ」と言いたくなる背景には、プライバシーが値上がりすると儲けが減って困る、という(おそらくは無自覚な)思いがあるんじゃなかろうか。

「ささいなこと」と言いつつ、一方で、必死で個人情報を吸い上げている。

プライバシーは、安く仕入れることができ、高く売れるからだ。

そんなに儲かるなら、まだまだプライバシーの値段を釣り上げられるはず。

倫理の話

たとえば、高級ホテルがすばらしいおもてなしを提供するため、VIPのお客様を尾行して、生活パターンを事細かに記録していた、というような場合。

誰にも害はなく、むしろ心地よいサービスを受けられる、けれども、理由は説明できないけれども悪だと感じる、のが倫理の話。

現実の尾行はダメで、ネットの尾行はアリなんだろうか。情報量が少ないから、解像度が低いから、許容できるのか。

ソーシャルなデータで解像度が上がると、ネットの尾行も許容できない行為に変わるかもしれない。

*1:気付いた時点で49個、その後いろいろ試して増減した。

Google アナリティクスで使われるクッキーについて __utma / __utmb / __utmz

公式な仕様は無さそう。ソースを読むのは厳しい。整形しただけでは全然読めなかった。

クッキー 4種類

現行バージョンの ga.js が使用するクッキーは、主に4つ。

  • __utma ユーザを識別。2年有効。
  • __utmb 今回のセッションを識別。30分有効。
  • __utmz どこから来たか。リファラ。6ヶ月有効。
  • __utmv カスタム変数。2年有効。

__utma, __utmb, __utmz は、ga.js が実行されたときに、無かったら作られる。

__utmv は、_setCustomVar() で作られる。

有効期間は、最後に更新した時点からカウントする。4つとも、GAにデータが送られる度に更新される。

たとえば __utma なら、ユーザが2年間サイトに来なかったら消える。2年以内に再度アクセスすると、そこからまた2年の有効期間が与えられる。

他に、

がある。

__utma

アクセスしたユーザを識別するためのクッキー。6個の数字をドット(.)で連結した値が設定される。

__utma=123456789.123456789.1234567890.1234567890.1234567890.1

数字は、

  • ドメインのハッシュ値
  • ランダムなユニークID
  • タイムスタンプ(初回)
  • タイムスタンプ(前回)
  • タイムスタンプ(今回)
  • セッションカウント

を表す。タイムスタンプはUNIXタイム

「2個目(ランダム) + 3個目(初回タイムスタンプ)」が「ビジターID」になる。

__utmb

今回のセッションを識別するクッキー。4つの数字をドット(.)で連結した値が設定される。

__utmb=123456789.1.10.123456789

数字は、

  • ドメインのハッシュ値
  • アクセス回数
  • 外部リンクをクリックした回数を10からカウントダウン?
  • タイムスタンプ

を表す。

3番目のカウントダウンは、サイトから外に出て行くクリック(アウトバウンドリンク) でイベントを発生させる回数を制限しているらしい。(参考1, 参考2, 参考3)

__utmz

流入元を識別するクッキー。

__utmz=123456789.1234567890.1.1.utmcsr=流入元ドメイン|utmgclid=アドワーズ用ID|utmccn=キャンペーン|utmcmd=メディア|utmccs=広告の種類|utmctr=キーワード

冒頭の数字は、

  • ドメインのハッシュ値
  • タイムスタンプ
  • セッションカウント
  • キャンペーンカウント

を表す。

セッションカウントはセッションが作成された回数。__utma の末尾とだいたい一致する。が、たまに違うこともある。なんで? → 期間が2年と半年で違うからか。__utma よりも短期の活動を記録している。

キャンペーンカウントは異なるキャンペーンからアクセスした回数。

後半は、

  • utmcsr (utm_source) ソース: ドメイン名、google、(direct)
  • utmccn (utm_campaign) キャンペーン: (organic)、(referral)、...
  • utmcmd (utm_medium) メディア: organic、referral、...
  • utmcct (utm_content) 広告の種類: リファラのパス
  • utmctr (utm_term) キーワード: 検索エンジンのキーワード
  • utmgclid アドワーズID

括弧内はクエリパラメータの名前。値を上書きできる。

キャンペーンは、別のリンクからアクセスすると書き換わる。

通常、キャンペーン Cookie はユーザーが検索エンジン、参照元ウェブサイト、またはキャンペーンのタグが付いた URL を通じてサイトにアクセスするたびに更新されます。ただし、ノーリファラーの場合は、こうしたキャンペーン ソースの情報が更新されることはありません。

http://support.google.com/analytics/answer/2731565?hl=ja

ソース

整形は簡単。

この状態で、しばらく頑張って読んでみたけど、難しかった。

(追記) 日本語コメント付き ga.js ソース解説 を作成されてる方が。すごすぎる。。

GitHub の公開鍵で暗号化する ghcrypt の処理内容

の続き。甘い物のことは忘れて、もうちょっとちゃんと書きます。

いくつかバージョンアップを行いました。暗号化はAESで行い、AES のパスフレーズを公開鍵で暗号化するようにしました。現在のバージョンは 0.5 です。

ghcrypt ファイル名 githubユーザ名(受信者)
ghcrypt ファイル名.enc.tar githubユーザ名(送信者)

で、暗号化・復号化を行います。

動作環境

OpenSSH の 5.6 以降が必須です。OpenSSL は 0.9.8 あたりで動作確認をしてます。

OpenSSH 形式の公開鍵を OpenSSL で使える PKCS#8 にエクスポートするために、 OpenSSH 5.6 以降が必須となっています。手元の OSX Lion には入ってましたが、Debian Squeeze は、まだ 5.5 のようでした。

この時点で簡単に使えるとは言えないかも……。

$ ssh -V
OpenSSH_5.6p1, OpenSSL 0.9.8r 8 Feb 2011

* Allow ssh-keygen(1) to import (-i) and export (-e) of PEM and PKCS#8
keys in addition to RFC4716 (SSH.COM) encodings via a new -m option
(bz#1749)

Python の変換ツールを作ってる方がいました。そんな難しくなさそうなので、自前で変換してもいいかもしれません。

インストール

特にインストールで必要な作業はありません。bin/ghcyrpt をパスの通ったディレクトリに置いてください。

処理内容

暗号化処理では、以下の処理を行っています。

alice が bob に sample.txt を暗号化して送ろうとしている場合。

1. ディレクトリを作る

f:id:koseki2:20130217211142p:plain

カレントディレクトリに sample.txt.enc というディレクトリを作成します。

既存のファイルやディレクトリが存在する場合はエラーメッセージを出して終了します。

2. 受信者 (bob) の公開鍵をダウンロード、変換

f:id:koseki2:20130217211143p:plain

GitHub から公開鍵を wget します。ユーザ名が間違っていた場合にエラーにするため、先にダウンロードします。

ダウンロードした公開鍵を sample.txt.enc/bob.keys に保存します。この鍵を ssh-keygen -m でPKCS#8 に変換し、 bob.keys.pem として保存します。

ssh-keygen -f bob.keys -e -m PKCS8 > bob.keys.pem || exit $?

3. AES 用のパスフレーズを生成、ファイルを暗号化

f:id:koseki2:20130217211146p:plain

以下のコマンドで sample.txt.enc/sample.txt.key にランダムなパスフレーズを書き込みます。長さは 117 バイト。

cat /dev/urandom | LANG=C tr -dc '[:graph:]' | head -c 117 > sample.txt.key || exit $?

生成したパスフレーズを使い、sample.txt を AES 256 CBC で暗号化します。

openssl aes-256-cbc -e -in sample.txt -out sample.txt.enc/sample.txt.enc -pass file:sample.txt.enc/sample.txt.key || exit $?

pass で指定するファイルは1行目しか使われないので要注意です。

openssl rand コマンドで生成したバイナリを直接パスフレーズとして使うことはできません。ランダムなバイト列を使うと、一文字目に改行が含まれていた場合に、パスフレーズが空になってしまいます(おそろしい)。

パスフレーズから、AES の鍵とIV が生成されます。aes 256 で 256 bit の長さを持つのは鍵であって、パスフレーズは好きな長さに設定できます。

パスフレーズが、どのくらい長いとベストなのかはわかりませんでした。パスフレーズが鍵と同じ 32 bytes だと短いかもしれません (ビット列と異なり、使える文字が限られているため)。117 bytes ほど長い必要はないかもしれません。

117 bytes は、1024 bit の公開鍵で暗号化できる最大サイズです。どんだけあてになるかわかりませんが、昔書いた記事を見つけました (117 bytes 以上は暗号化できないことは確認しています)。

4. AES パスフレーズを公開鍵で暗号化

f:id:koseki2:20130217211147p:plain

rsautl コマンドで sample.txt.key を暗号化します。

openssl rsautl -encrypt -in sample.txt.key -out sample.txt.key.enc -inkey bob.keys.pem -pubin || exit $?

最初から公開鍵で sample.txt を暗号化しないのは、上で書いたとおり、公開鍵で暗号化できるサイズに限度があるためです。

5. 秘密鍵を使って、暗号化したファイルに署名

f:id:koseki2:20130217211148p:plain

以下のコマンドで sample.txt.enc に署名します。

openssl sha1 -sign /home/alice/.ssh/id_rsa sample.txt.enc > sample.txt.enc.sig || exit $?

6. 不要なファイルを消して tar 生成

f:id:koseki2:20130217211201p:plain

  • sample.txt.key.enc RSA暗号化済みのAES鍵
  • sample.txt.enc AES暗号化済みの入力ファイル
  • sample.txt.enc.sig 署名

を格納した tar ファイルが生成されます。

7. 復号化

暗号化とほぼ同じです。

  • tar を展開
  • alice の公開鍵をダウンロード、PKCS#8 変換
  • 署名を検証。ほんとに alice から来たのか。
    • openssl sha1 -verify alice.keys.pem -signature sample.txt.enc.sig sample.txt.enc
  • AES 鍵を bob の秘密鍵で復号
    • openssl rsautl -decrypt -in sample.txt.key.enc -out sample.txt.key -inkey /home/bob/.ssh/id_rsa
  • AES 鍵で元のファイルを復号
    • openssl aes-256-cbc -d -in sample.txt.enc -out sample.txt -pass file:sample.txt.key
  • 後片付け。tarで展開したディレクトリを削除。

FAQ

Q. 安全ですか?

A. わかりません。

… 単に OpenSSL のコマンドを順に実行してるだけなので、そんな無茶はしてないと思うのですが、多くの人の目に触れないと安全ではないと思います。

GitHub のユーザ名を指定してファイルを暗号化するツール ghcrypt を作った

鳩舎さんで、GitHub の公開鍵を簡単に取得できるのを知りました。

で、ファイルにちょっとした暗号化をかけたいことありますよね。パスワード付き zip よりは、もうちょっとマシなのを使いたい。でも GPG はなんかむつかしいし(印象)、相手がインストールしてない気がする (自分もインストールしてない)。

というわけで。 GitHub の公開鍵を使って簡単にファイルを暗号化するスクリプトを書きました。

暗号化したいファイル名と送りたい相手の GitHub ユーザ名を指定して、暗号化と署名を行います。

$ ghcrypt loveletter-to-koseki.txt koseki

--2013-02-14 00:00:00--  https://github.com/koseki.keys
Resolving github.com...
Connecting to github.com|xxx.xxx.xxx.xxx|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 380 [text/plain]
Saving to: `loveletter-to-koseki.txt.enc/koseki.keys'

100%[========================================================>] 380         --.-K/s   in 0s

2013-02-14 00:00:00 (xxx MB/s) - `loveletter-to-koseki.txt.enc/koseki.keys' saved [380/380]

----------------------------------------------------------------
Reciever: koseki
  https://github.com/koseki
  2048 5a:b0:0a:cf:8d:64:37:5b:06:ec:b4:d1:cf:96:25:81 loveletter-to-koseki.txt.enc/koseki.keys (RSA)
----------------------------------------------------------------
Enter pass phrase for /path/to/private_key:

Successfully Encrypted and Signed!
  loveletter-to-koseki.txt --> loveletter-to-koseki.txt.enc.tar

(指定したファイル名).enc.tar というファイルが生成されます。tarの中に暗号化したファイルと署名が入ってます。

受け取った相手は、送り主のユーザ名を指定して署名を検証し、復号化を行います。

$ ghcrypt loveletter-to-koseki.txt.enc.tar alice

--2013-02-14 00:00:00--  https://github.com/alice.keys
Resolving github.com...
Connecting to github.com|xxx.xxx.xxx.xxx|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 380 [text/plain]
Saving to: `loveletter-to-koseki.txt.enc/alice.keys'

100%[========================================================>] 380         --.-K/s   in 0s

2013-02-14 00:00:00 (xxx MB/s) - `loveletter-to-koseki.txt.enc/alice.keys' saved [380/380]

----------------------------------------------------------------
Sender: alice
  https://github.com/alice
  2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx: loveletter-to-koseki.txt.enc/alice.keys (RSA)
----------------------------------------------------------------
Verified OK
Enter pass phrase for /path/to/private_key:

Successfully Verified and Decrypted!
  loveletter-to-koseki.txt.enc.tar --> loveletter-to-koseki.txt

GitHub の秘密鍵ファイルのパスを $HOME/.ghcrypt に書いておきます。

$ echo /home/koseki/.ssh/id_rsa > ~/.ghcrypt
$ chmod 400 ~/.ghcrypt

あるいは、--key で秘密鍵を指定します。

$ ghcrypt --key ~/.ssh/id_rsa loveletter-to-koseki.txt koseki

現状、鍵の長さより大きいファイルは暗号化できません。AES の鍵を生成するといいと思うんだけど、まだやってない。(追記: やりました。)



偶然にも今日はバレンタインデーですね。まだ何ひとつ受け取っておりませんが、 GitHub ユーザの女子の皆さんは、僕にこっそり伝えたいメッセージがあったのではないでしょうか。

ユーザ名は koseki ですよ。

英語で RSpec を書くために例文一覧を出力する

gems ディレクトリの */spec/**/*_spec.rb ファイルに対して 'it .* do' を grep する。

cd ~/.rvm/gems/ruby-1.9.3-p327/gems
find */spec -type f -name '*_spec.rb' | xargs grep -ho 'it .* do' | sort | uniq | less

みたいな感じ。以下のような出力が得られる。

:
it "accepts a URL as the path" do
it "accepts a block to change output" do
it "accepts a block" do
it "accepts a body" do
it "accepts a class as argument with a task to invoke" do
it "accepts a class as argument without a task to invoke" do
it "accepts a color as status" do
it "accepts a local file path with spaces" do
it "accepts a port" do
it "accepts a secure URL as the path" do
it "accepts a session without changes to tracked parameters" do
it "accepts a stub for save" do
it "accepts a stub for the primary_key" do
it "accepts a stub id" do
it "accepts a switch <value> assignment" do
it "accepts a switch=<value> assignment" do
it "accepts a timeout argument to #stop" do
it "accepts ajax requests without a valid token" do
it "accepts and executes a 'legal' %\w+% encoded instruction" do
it "accepts and interacts with a matcher" do
it "accepts array value" do
it "accepts arrays" do
it "accepts class and module objects" do
it "accepts conjoined short switches with input" do
it "accepts conjoined short switches" do
it "accepts data as a block" do
it "accepts explicitly provided cookies" do
it "accepts false as boolean()" do
it "accepts fixnum as instance_of(Fixnum)" do
it "accepts fixnum as kind_of(Numeric)" do
it "accepts float as an_instance_of(Numeric)" do
it "accepts get requests with 304 headers" do
it "accepts get requests with json responses with a local referrer" do
it "accepts get requests with json responses with no referrer" do
it "accepts hash value" do
it "accepts hashes" do
it "accepts http remote sources" do
it "accepts https remote sources" do
it "accepts inputs in the human name format" do
it "accepts options when assembling the parse tree" do
it "accepts params and builds query strings for GET requests" do
it "accepts params and builds url encoded params for POST requests" do
it "accepts params in the path" do
it "accepts post form requests with a remote referrer and correct authenticity_token field" do
it "accepts post form requests with correct authenticity_token field" do
it "accepts post requests with a local referrer" do
it "accepts post requests with a remote referrer and correct X-CSRF-Token header" do
it "accepts post requests with correct X-CSRF-Token header" do
it "accepts post requests with no referrer" do
it "accepts post requests with the same host in the referrer" do
it "accepts raw input in params for GET requests" do
it "accepts raw input in params for POST requests" do
it "accepts string as anything()" do
:

単語で検索すると、真似できそうなセンテンスが見つかる。また、 cause error と raise error のどっちにするか、みたいなことで悩まずに済む。

$ grep 'raise.*error' samples.txt | wc -l
     129
$ grep 'cause.*error' samples.txt | wc -l
       3
$ grep 'pass.*arg' samples.txt | wc -l
      95
$ grep 'pass.*param' samples.txt | wc -l
       9

うれしい。

Ruby の Array#index は、要素とブロックを渡すの、どっちが速いの?

Array#index を使って、配列に含まれる要素の位置を取得したい。配列の要素が配列やハッシュで、一意に識別可能なIDが含まれる場合、探し方は、要素を直接渡すのと(==で比較する)、ブロックを渡す方法がある。

# ハッシュをそのまま渡す。
array.index hash

# ハッシュの値をブロックで比較する。
array.index { |hash2| hash[:id] == hash2[:id] }

どっちが速いのか気になったので、ベンチマークをとった。Ruby 1.9.3p283。

自分の予想は「配列の要素に含まれる要素数がある程度多くなると、ブロックの方が速くなる」。

実際には、要素の要素数と関係なくブロックを渡す方が速かった。

$ ruby array_index_bench.rb
                user   system    total       real
value value 0.140000 0.000000 0.140000 ( 0.144671)
value block 0.250000 0.000000 0.250000 ( 0.246818)
array value 1.660000 0.000000 1.660000 ( 1.659921)
array block 0.290000 0.000000 0.290000 ( 0.295605)
hash value  1.870000 0.000000 1.870000 ( 1.866465)
hash block  0.370000 0.000000 0.370000 ( 0.373319)

ただの数値の配列だとブロックを渡すよりも値を直接渡す方が速い。配列やハッシュではブロックを渡す方が速い。

まとめ

配列の要素が配列やハッシュで一意に識別できる値が含まれる場合は、

array.index hash

と書くより、

array.index { |hash2| hash[:id] == hash2[:id] }

と書いた方がよさそう。