トリビア:Google+アカウントにアップデートするときは気をつけないと全データが全部飛ぶ

Posted on

 泣きたい

 GoogleのGoogle+へのプッシュ具合は最近すごいですよね。今までほとんどGoogle+はつかっていなかったのですが、最近必要にせまられたので登録してみました。

 Google+ができてしばらくたってからのアカウントでは、gmailのアカウントでもPicasaのアカウントでも登録時にGoogle+にも一緒に登録することが必要になっていますが、比較的昔から使っているアカウントの場合には、Google+へ追加で登録を行う(Google曰く「アップデート」)ことになっています。

 今回、ふるいgmailアカウントをGoogle+にアップデートしようとしたら悲しい自体になったので周知徹底等させて頂きたく存じ上げます(敬語)

 Google+の登録時の画面で、性別と年齢を入れるわけですが…

20120711_01.png

 はまちちゃんも実名だけはやめとくよう言うし、私も実際その通りだと思うので、年齢も性別も毎度適当に入れています。で、今回は歌詞になってて覚えやすい鉄腕アトムの誕生日を入れて登録してみたのですが…

20120711_02.png

 …ん?

 20120711_03.png

 なん…だと…10年間分のメール…が…

 どうやら13歳以上じゃないと使えない、ということらしいです。小学生はgmailを使ってお友達とメールすることができないらしい!です。うーん、リアル小学生のときyahoo!mailもhotmailも取ったような気がするのですが…。Google先生は厳しいですね。Google社内にスーパー小学生エンジニアとか居ないのかしらん(ぉ

 Googleに身分証明書を送付するなどすれば解除と削除回避は可能だそうですが、Googleにそこまで個人情報を教える気にはどうしてもなれませんし、そもそも偽名だし…であきらめるしかなさそうです。規約上たぶん本名を入れることになってると思うので、私の自業自得ではあるのですが…悲しい。

 そういえば上の画像だと「波動関数 ぷさい」ですが、最初これははじかれました。Google+の命名ルールに従っていない、もっというと「本名じゃないでしょそれ」と言われてしまいました。でも昨今の「DQNネーム」とやらを見てると、これぐらい変わった名前の人がいてもおかしくないと思うのだけど…Googleに身分証明書送らないとアカウント作らせて貰えないのかな??そこまでしてやるもんんかなあ?

 ファーストサーバの中の人の気持ちがわかった気がします


HTTP1.1のLocationヘッダは、絶対URLでないとRFC違反

Posted on

さきゅばす2のバグ対処で知ったお話です。とりあえず、HTTPの基礎知識はあることを前提にします。

さきゅばす2では、公式動画のDLがどうしても出来ませんでした。こんなエラーが出ちゃうんです。

[E][    PyBridgeImpl] Python says:
(略)
HTTPError: HTTP Error 302: Found - Redirection to url '/watch/1339405721' is not allowed

どうやらリダイレクションの段階で問題が発生してるみたいですねぇ。

HTTPでのリダイレクション

とあるページにアクセスした時に他のページにジャンプしなおさせる「リダイレクション」ですが、このリダレクションはHTTPはレスポンスヘッダで301,302,303,307のレスポンスコードを返した上で、Locationヘッダを設定することで実現しています。

どこかのページのレスポンスヘッダで、

Location: http://www.google.com/

こういうふうなヘッダを返すと、そのページにアクセスした人がGoogleに無条件で飛ばされるわけですね。

で、ニコニコ動画のリダイレクションでは、

Location: /watch/1339405721

となっていて、http://www.nicovideo.jp/watch/1339405721 にジャンプするようになっていました。うーん、特に問題なさそう。

Locationヘッダは絶対パスしか認められない。

…ところがどっこい、実はLocationヘッダのURLは絶対パスしか認められないのです。RFC見ましょうか。

Location       = "Location" ":" absoluteURI

で、このabsoluteURIはRFC2396: Uniform Resource Identifiers (URI): Generic Syntaxで定義されておりまして、

absoluteURI   = scheme ":" ( hier_part | opaque_part )

ということで、URIスキーム(httpとかftpとか)から始まる絶対URIであることがわかります。

とはいえ、色々調べてみると、携帯とか一部のブラウザを除くと大体相対パスでも動くそうで、絶対URIを作成時に予測するのが難しい、他人に配布するスクリプトなどでは相対パスで指定していることが多いそうです。

 

ニコニコ動画の場合は絶対URIでも良いと思うのですが今回は相対パスで指定されていて、ふつうのブラウザなどではこれで意図通りに動くのですが、さきゅばす2のPythonでは最近のバージョンまで相対パスに対応していなかったため問題になったようです。で、最新のバージョンでは相対パスに対応しているので、配布バイナリを最新バージョンに差し替えることにしました。

で、ほかのヘッダではどうなってるの?

HTTPのヘッダには、ほかにもいくつかパスを指定できるものがありましたよね。いくつか調べてみました。

Request-URI

リクエストURIは、GET ****** HTTP/1.1みたいな形式で指定されるときの、あのURIです。

Request-URI    = "*" | absoluteURI | abs_path | authority

なんと…。実は絶対URI指定でも良いのですね。たまに絶対URIでのリクエストがこのサーバに飛んでくるのですが、てっきり不正なリクエストなんだと思ってました。…とはいえ、ほとんどのクライアントは絶対パスで取得するのがふつうなので、ちょっと警戒すべきだとは思いますけど…。

 

Content-Location:

Locationと似てますが別物です。リクエストされたコンテンツが別のところからも取得可能な時に使われる…そうですが、実際使われてるのを見たことがありません…。だれか教えて(ぇ

Content-Location = "Content-Location" ":"
( absoluteURI | relativeURI )

こっちは相対URIも可能です。同じサーバであることが自然だからなのかなあ。

Referer

リファラです。ほかのページのリンクなどをたどって来たことを示すわけですが…

Referer        = "Referer" ":" ( absoluteURI | relativeURI )

なんと!これも相対URIはOKでした。とはいえ、世の中のクライアントは大体絶対URIじゃないでしょうか?

以上です。たまにはRFC読んでみると意外な発見がいろいろありますね。

追記:RFC7321では相対URLが認められている

その後2012に出たRFC7231では相対URLもOKになりました。以下、引用です:

7.1.2. Location

   The "Location" header field is used in some responses to refer to a
   specific resource in relation to the response.  The type of
   relationship is defined by the combination of request method and
   status code semantics.

     Location = URI-reference

   The field value consists of a single URI-reference.  When it has the
   form of a relative reference ([RFC3986], Section 4.2), the final
   value is computed by resolving it against the effective request URI
   ([RFC3986], Section 5).

   For 201 (Created) responses, the Location value refers to the primary
   resource created by the request.  For 3xx (Redirection) responses,
   the Location value refers to the preferred target resource for
   automatically redirecting the request.

   If the Location value provided in a 3xx (Redirection) response does
   not have a fragment component, a user agent MUST process the
   redirection as if the value inherits the fragment component of the
   URI reference used to generate the request target (i.e., the
   redirection inherits the original reference's fragment, if any).

   For example, a GET request generated for the URI reference
   "http://www.example.org/~tim" might result in a 303 (See Other)
   response containing the header field:

     Location: /People.html#tim

   which suggests that the user agent redirect to
   "http://www.example.org/People.html#tim"

Lazy aKari:わぁいLazy K あかりLazyKインタプリタだいすき

Posted on

Abstract

CPUのクロック数が頭打ちになり、1コアあたりの性能を向上させるよりもコア数を増やす事による並列性能向上が行われるようになった昨今では、並列化の行い易い純粋関数型プログラミング言語が注目されています。本研究で題材とするLazyKは、トークンが4つというシンプルさでありながら、チューリング完全な純粋関数型プログラミング言語です。

一方、近年のアニメシーンにおいて、アニメ本編よりもインターネット上での罵声の浴びせかけあいやステマばかりが着目され、アンチと信者のせめぎあいがより激しくなり荒廃が進んでいます。

7/2より放送されている「ゆるゆり♪♪」の主人公赤座あかりは、彼女の必殺技「\アッカリ~ン/」によって可視光における強い参照透過性を実現し、彼女のすべてを愛す性格によって、世界に愛をもたらしています。

本研究では、LazyKに赤座あかりの愛を組み合わせた独自言語「Lazy aKari」を実装することで、LazyKの啓蒙と世界に愛を広めました。

いつも通りの「トークン変えただけのゴミ言語のお時間」です。Brainfuckでやってる事が多い気がしますが、毎度毎度Brainfuckでやるのも流石に秋田ので別のにしました。トークンが4つで調度良かったのでLazyKです。で、毎度毎度手続き型で書くのも秋田ので今回はLISPで書いて見ました。ほとんどLISPの機能を使ったので随分楽ちんな実装となっております。

Scheme処理系の一つであるgaucheを使ってます。

Unlambdaスタイルのみに対応しております。トークンの対応は次の通り

  • わぁい⇨`
  • うすしお⇨s
  • あかり⇨k
  • だいすき⇨i
$ gosh akari.scm <ソースファイル>

として、入力を入れたらCtrl+D(WindowsではCtrl+Zらしい)を押して入力を確定すると、プログラムが実行されて結果が表示されます。

サンプル:echoプログラム

入力をそのまま返します。

大好き

これを保存してgosh akari.scm echo.txtとして実行し、入力したらCtrl+D(WindowsではCtrl+Z)を押してね。入力した結果がそのまま表示されます。

% gosh akari.scm echo.akari
yryr[Ctrl+D]
yryr

大好きはエコー…。そう、人と人との絆は、相互承認なのです(鼻で笑いながら

サンプル:Hello World

Hello Worldです。メッセージ変えたかったのですがLazyKは書ける気がしなかった()のでWikipediaのをそのまま使いました

わぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好きわぁいあかりわぁいわぁいうすしおわぁい
 あかりわぁいわぁいわぁいうすしお大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかり
 うすしおあかり大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁい
 うすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいわぁいうすしおわぁい
 わぁいうすしお大好き大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり
 大好きわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好きわぁいあかりわぁいわぁいうすしおわぁい
 わぁいうすしおわぁいあかりうすしおあかりわぁいわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかり
 うすしおあかり大好きわぁいわぁいうすしおわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしおわぁい
 あかりうすしおあかり大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁい
 わぁいわぁいうすしお大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり
 大好きわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好きわぁいあかりわぁい
 わぁいうすしおわぁいあかりわぁいわぁいわぁいうすしお大好き大好きわぁいわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁいわぁいうすしお大好き
 大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁい
 うすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいあかりわぁいわぁいうすしお
 わぁいわぁいうすしお大好きわぁいあかりわぁいわぁいうすしおわぁいあかりわぁいわぁいわぁい
 うすしお大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり
 大好きわぁいわぁいわぁいうすしお大好き大好きわぁいわぁいうすしおわぁいわぁいうすしお
 わぁいあかりうすしおあかりわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり
 大好きわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好きわぁいあかりわぁいわぁい
 うすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしおわぁいあかりわぁい
 わぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁいうすしおわぁい
 わぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしおわぁいあかりわぁいわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁいわぁいうすしお大好き
 大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいあかりわぁいわぁいうすしおわぁい
 わぁいうすしお大好きわぁいあかりわぁいわぁいわぁいわぁいうすしおわぁいわぁいうすしおわぁい
 あかりうすしおあかりわぁいわぁいわぁいうすしおわぁいわぁいうすしお大好き大好き大好き
 わぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいわぁいうすしお大好き大好き
 わぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいあかりわぁいわぁいうすしお
 わぁいわぁいうすしお大好きわぁいあかりわぁいわぁいうすしおわぁいあかりわぁいわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁいわぁいうすしおわぁい
 わぁいうすしお大好き大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁい
 あかりうすしおあかり大好きわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好き
 わぁいあかりわぁいわぁいうすしおわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお
 わぁいあかりうすしおあかりわぁいわぁいうすしおわぁいあかりわぁいわぁいうすしおわぁい
 わぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁいうすしおわぁいわぁいうすしお
 わぁいあかりうすしおあかりわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり
 大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいわぁい
 うすしおわぁいわぁいうすしお大好き大好き大好きわぁいわぁいうすしおわぁいわぁいうすしお
 わぁいあかりうすしおあかり大好きわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好き
 わぁいあかりわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしお
 わぁいあかりわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁい
 うすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしおわぁいあかりわぁいわぁい
 うすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁいわぁいうすしお大好き大好き
 わぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしおわぁいわぁい
 うすしおわぁいあかりうすしおあかり大好きわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好き
 わぁいあかりわぁいわぁいうすしおわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしお
 あかり大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしお
 わぁいあかりわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいわぁいうすしお大好き大好きわぁいわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり
 大好きわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好きわぁいあかりわぁいわぁいうすしおわぁいあかり
 わぁいわぁいわぁいうすしお大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好き
 わぁいわぁいわぁいうすしお大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしお
 あかりわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいあかりわぁいわぁい
 うすしおわぁいわぁいうすしお大好きわぁいあかりわぁいわぁいわぁいうすしおわぁいわぁいうすしおわぁい
 あかりうすしおあかり大好きわぁいわぁいうすしおわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお
 わぁいあかりうすしおあかり大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり
 わぁいわぁいわぁいうすしお大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうす
 しおあかり大好きわぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好きわぁいあかりわぁいわぁい
 うすしおわぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいうすしおわぁいあかりわぁいわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁいわぁいうすしおわぁいわぁいうすしお
 大好き大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好き
 わぁいあかりわぁいわぁいうすしおわぁいわぁいうすしお大好きわぁいあかりわぁいわぁいうすしおわぁい
 あかりわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいわぁいうすしお
 わぁいわぁいうすしおわぁいあかりうすしおあかりわぁいわぁいわぁいうすしお大好き大好きわぁいわぁい
 うすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好きわぁいあかりわぁいわぁいうすしおわぁい
 わぁいうすしお大好きわぁいあかりわぁいわぁいわぁいうすしお大好き大好きわぁいわぁいわぁい
 うすしお大好き大好きわぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好き
 わぁいあかりわぁいわぁいわぁいうすしお大好き大好きわぁいわぁいわぁいうすしお大好き大好き
 わぁいわぁいうすしおわぁいわぁいうすしおわぁいあかりうすしおあかり大好き

どうしたあかり。たまにはのり塩も食べないと。

% gosh akari.scm hello.akari
[Ctrl+D]
Hello, world!

かんたんなかいせつ

LazyKは上にあるように、4つのトークン`skiをつかいます。で、そのうちskiの3つは関数です。LISPで書くとこんな関数。

(define (S x) (lambda (y) (lambda (z) ( (x z) (y z)))))
(define (K x) (lambda (y) x))
(define (I x) x)

で、`というのは関数呼び出しを表します。つまり、`ikは(I K)で、“skiは( (S K) I)のことで、`s`kiは(S (K I) )ということです。関数は必ず1つだけ引数を取ります。以下可読性を重視してLISP形式で書きます。

Iは引数をそのまま返す関数なので簡単ですね。

Kは関数を返す関数です。つまり、(K 1)の戻り値は (lambda (y) 1)という「関数」で、((K 1) 2)としてさらに戻ってきた関数を呼び出すと1(=x)という結果になります。なんでこんな面倒な事をするかというと、LazyKの世界では関数は引数を1つしか取れないのですが、Kという関数にはどうしても2つ引数を取らせたかったからです。LazyKでは関数は関数を返すことができるので、関数を返す関数を作ることで引数が1個しかとれない問題を回避しています。これをカリー化と言うそうです。

Sはちょっと厄介ですね。((S K) K)が関数Iと等しい関数であることを確かめると理解できると思います。

((S K) K) -> (lambda (z) ( (K z) (K z))) ;定義にしたがって、xとyをKに置き換えただけ
-> (lambda (z) ( (lambda (w) z) (K z))) ;最初の(K z)を展開した。内側のラムダ式でwは使われないことに注目。
-> (lambda (z) z)
-> これはIそのもの

…うーん、面倒ですね。

数字は?

LazyKは上記でみた3つの要素しかありません。数字というリテラルはありません。えっ、でも計算くらいできないと困るじゃん。

そこでLazyKでは、数をチャーチ数というので表します。数とありますがやっぱり関数で、この関数に別の関数fを渡すと、fをn回適用してくれる関数を返してくれる関数です。「関数」がゲシュタルト崩壊してきてはあ?って感じですね。たとえば、チャーチ数で3を表す関数をchurch-3は、引数として関数fをとり、「f(f(f(x)))を返す関数」を返してくれます。つまり、渡す関数を「引数に1を足して返す関数」にすると、

(define (adder x) (+1 x)) ;1を足した引数を返す
((church-3 adder) 0) -> 3

というわけです。ちなみに、チャーチ数の0は(K I)です。

リストは?

よくわからないんですけどこれも関数で表します。LISPのcar/cdrなリストと同じような構造で、具体的にはリストの関数を_LIST_とすると、(_LIST_ K)とするとcarが、(_LIST_ (K I))とするとcdrをしたことになるらしいです…。同様にconsも定義できるそうです。 終了条件がわからない(lispでのpair?はどうやるの?)ので誰か教えてください。

入出力は?

入出力は上で紹介したチャーチ数とリスト構造を使います。LazyKのプログラムは関数を組み合わせて作られる大きな大きなひとつの関数なので、これへ引数として入力値のASCIIコードをチャーチ数で表したもののリストを入れて実行されます。で、その戻り値(チャーチ数のリスト)が出力というわけです。

なので、「大好き」(=i)だけのプログラムは、入力値をそのまま返すechoプログラムになったわけですね。

というかですね

LazyKは情報がなさ過ぎます。あと実をいうと二期はまだ見てないです(

二期みた

こwwwwwねwwwwwこwwwwwwwちゃんwwwwwwwwwwwwwwwwwwwたちwwwwwwwwwwwwwwwwwww


Freenetでは、どうやって匿名性を確保しているの?

Posted on

 今日はFreenetの話です。な、なぜいきなり…。なんとなく。一足早い夏休みのじゆうけんきゅうです。

おしながき

 Freenetは、ピュアなP2Pによる、匿名通信を実現するソフトです。WinnyやShareなどよりも遥かに匿名性が高く、Wikipedia曰くあの中国ですら追跡はできないらしいです†1

 で、今回公式サイトに転がってるオリジナル論文を読んだので、論文に書いてあった事とか、論文だけでは分からなかったので実装を直接触って調べた話を書いておきます。

Freenetのコミュニケーションの基本単位は「メッセージ」

 Freenetの基本的なイメージは、ネット上にたくさんの「ノード」と呼ばれるコンピュータがあって、それぞれが他のいくつかのノードと繋がっており、全体として大きな網目状のネットワークになっている、というものです。

20100526_01.png

 これらの中では、ノード同士が「メッセージ」をバケツリレー式にやり取りすることでコミュニケーションしています。TCP/IPとかのパケット通信と似てます。

 「メッセージ」には検索や追加など、いくつか種類があるのですが、どのメッセージも必ず次の属性は持っています。

  • メッセージを区別するユニークなID
  • メッセージの送信先
  • メッセージの送信元
  • HTL(Hops to Live)

 最後のHTLは、IPのTTLと大体同じです。メッセージがノードを通過するたびに一つずつ減っていき、0になった時点でメッセージが破棄され、破棄したノードは「失敗したよ」というメッセージを送信元に送り返します。論文だとTTLと表現されているのですが、実装ではHTLとなっているのでこちらで統一します。

基本的には「多段串」とかと同じ感じ

 匿名性の基本原理は、いわゆる「多段串」とあまり変わらないようです。

 この図において、AさんはCさんが送信したメッセージを、Bさんを経由して受信しています。BさんはAさんに、Bさん自身のアドレスしか教えておらず、送信者がCさんなのか、実はBさんとつながった別のノード、Dさんなのかは教えません。

20100526_02.png

 さらに言えば、BさんはCさんがオリジナル送信者なのかも知りません。実は、CさんもBさんと同じように、他の誰か、例えばEさんのメッセージを転送してるだけなのか、Bさんには分かりません。

 これを何回も繰り返すことで誰がオリジナルの送信者なのかどんどん分かりづらくなっていく、というわけです。

隣のノードへ対してはどうやって発信者を隠すの?

 私が疑問に思ったのは、自分のすぐ隣のノードには、自分がオリジナル発信者であるメッセージはわかってしまうのでは、ってことです。もしHTLの初期値が固定なら、隣のノードが、私から発信されたHTL=初期値のメッセージを受け取った場合、そのメッセージは間違いなく私がオリジナル発信者†2であるとバレてしまう可能性があると思います。

20100526_03.png

 この図で、BさんはCさんからHTL=18のメッセージを受け取っていますが、これはFreenetのデフォルトのHTL初期値と同じです。と、言う事は、このメッセージはまだ一度もHTLが減っていないメッセージなので、Cさんがオリジナル送信者であると推測できてしまうのでは無いでしょうか…?もちろん設定は変えられるので、必ずしもCさんがオリジナル送信者であるとは言い切れませんが、その可能性は高いと言えてしまいそうです。

 これは元の論文には何も書いていなかったので、実際にソースコードを読んで調べてみました。

とりあえず読む

 まず、HTLの初期値はどこで決定されるのでしょうか。freenet/node/Node.java内のこちらです。

        maxHTL = nodeConfig.getShort("maxHTL");

 設定値で固定です。…やはり、私の指摘したような問題が起こるのでしょうか?

 HTLを減らしているのは、同じソース内の、

    public short decrementHTL(PeerNode source, short htl) {
        if(source != null)
            return source.decrementHTL(htl);
        // Otherwise...
        if(htl >= maxHTL) htl = maxHTL;
        if(htl <= 0) {
            return 0;
        }
        if(htl == maxHTL) {
            if(decrementAtMax || disableProbabilisticHTLs) htl--;
            return htl;
        }
        if(htl == 1) {
            if(decrementAtMin || disableProbabilisticHTLs) htl--;
            return htl;
        }
        return --htl;
    }

 このメソッド。自分がオリジナル送信者の時はsource==null、転送するメッセージの場合はsource != nullみたいです。

 自分がオリジナル送信者のとき、source==nullなので処理は移譲されずこのメソッドが最後まで実行されます。decrementAtMaxがtrueな時に予めHTLがひとつ減らされる処理が入っているようです(自分が送信者なので、HTL=maxです)。これは、自分がオリジナル送信者であるメッセージについて、HTLを一つあらかじめ減らしておくことで「いえ、これは他の誰かから転送したメッセージですよ」と言っている事になります。

 ただし、このdecrementAtMaxはFreenetの起動時に決定されるパラメータ†3で、それ以降変更がないので、これだけではあまり十分であるとは言えないように思います。もしこれがFalseになった場合、やはり自分がオリジナル送信者であるメッセージだけ、HTL=最大(初期値)のメッセージを送る事になってしまうのでは?

 そこで、source != nullの時の移譲先を見てみましょう。freenet/Node/PeerNode.javaにあります。

    /**
    * Decrement the HTL (or not), in accordance with our
    * probabilistic HTL rules.
    * @param htl The old HTL.
    * @return The new HTL.
    */
    public short decrementHTL(short htl) {
        short max = node.maxHTL();
        if(htl > max)
            htl = max;
        if(htl <= 0)
            return 0;
        if(htl == max) {
            if(decrementHTLAtMaximum || node.disableProbabilisticHTLs)
                htl--;
            return htl;
        }
        if(htl == 1) {
            if(decrementHTLAtMinimum || node.disableProbabilisticHTLs)
                htl--;
            return htl;
        }
        htl--;
        return htl;
    }

 びっくりするくらい同じコードでした†4。このコードでは、隣のノードから受信したメッセージにおいても、HTLが最大(初期値)だったときに、HTLを減らさずに送る事がある事を示しています。つまり、隣のノードから来たHTL=最大(≒隣のノードがオリジナル送信者である可能性がある)のメッセージについて、HTLを最大値のままにしておくことで「いえ、これは私がオリジナル送信者なんです!」と言ってることになります。また、このパラメータは接続先ノードごとに設定しなおされるため、十分に掻き乱されると考えられます。

 このふたつが組み合わさることで、HTL=最大のメッセージを受け取った場合でも、そのノードがオリジナル送信者かどうか、もはやわからなくなります。他の誰かのメッセージをHTLを減らさずに転送したものかもしれないし、自分のかもしれないし、ということですね。

 さらに、隣のノードもそのように詐称するので、HTL=最大のメッセージを送ってきたノードがオリジナル送信者かかどうかはもちろん、直接隣接するノードかすらも分かりません†5。十分そうですね。

まとめ

 Freenet上では「メッセージ」をやり取りすることで情報が交換される。各メッセージはHTLという、IPのTTLに似たパラメータを持つが、オリジナル送信者の匿名性を守るため、最大HTLのメッセージについてはランダムで減らしたり減らされなかったりする。

まだ残る謎

 htl=1(メッセージが破棄される瀬戸際)のときにもランダムで減らしたり減らさなかったりしてるみたいですが、なぜ…??

どっちかっていうと鍵探索の方が技術的には面白いかも

 今回は論文を読んでいて疑問に思ったのが匿名性の部分だったのでそちらを書きましたが、論文全体を読んだ印象としては、どうやって中央サーバのないP2P上で検索するための「キー」とそれに対応した「情報」を結びつけ、検索させるのか、の方が技術的に面白いな、と思いました(小学生レベルの感想)。

その他

  • System.err.print()を使うとrun.sh consoleで起動したときのログで表示されるよ。
  • †1: 公式サイトの言語が中国語、フランス語、スペイン語なのがなんとなく印象的…
  • †2: 誰かのを転送したわけではないってこと
  • †3: maxHTLの設定を読み込む次の行でrandを使って決定されています
  • †4: でもちょこっとだけ変数名違う…。
  • †5: そのノードも詐称してるかもしれないからです

さきゅばす 2.0β1を公開しました。

Posted on

 先日のニコニコ超会議でお話した「さきゅばす2」ですが、やっと一般公開するための作業が終了したので公開します。

 DLはさきゅばす公式サイトから

大きく変わったフィーチャーをご紹介

ニワン語へ一部対応しました。

 ニコニコ動画内で使える謎の言語ニワン語に対応しました。対応命令はまだ限られていますが、ニコニコ超会議でもご紹介したProjectNivaや、Nicocococococo!などの動作は確認しております。

正式に投稿者コメントに対応しました。

 上記の変更に合わせ、投稿者コメントにも対応しました。

フルスクラッチで書き直し、Javaのインストールが不要になりました。

 従来のJavaとCを廃止し、すべてをC++とPythonで開発しなおしました。このため、従来必要だったJavaのインストールが不要になっています。(配布サイズが絶望的ですが…)。

動画の変換設定やNGの設定が非常に柔軟になりました。

 Pythonスクリプトで記述するようになったため、非常に複雑なルールも記述できるようになりました。ng-scriptフォルダやrecipeフォルダのサンプルをご覧ください。

フレームレートの低い動画でもスムーズに変換できるようになりました。

 元の動画のFPSが極端に低い(1FPSとか)場合、従来のさきゅばすではそのFPSに合わせてでしか変換できず、カクカクになってしまいましたが、今回書きなおしたため、任意のFPS(デフォルトで25FPS以上)で変換されるようになりました。上記のNicocococococo!でもこの機能が使われています。

変換する動画を一度に指定してしておけるようになりました。

 もうauto.batはいりません。複数の動画IDを登録しておけば、勝手に最後まで変換してくれます。

ありそうでなさそうでやっぱりありそうな質問と答え

使い方は?

 やっつけですが一応使い方を書いておきましたので参考にしてください。サポートは2chのスレでお願いします。

「***」っていう動画が変換できないんだけど…

 バグの投稿はこちらで受け付けています(匿名でできます)。Blogとかメールとか2chに投稿していただいても大丈夫ですが、たぶんこっちに登録した方が早く対処されると思います(他のチャンネルまで目を通しきれてないです、すいません…) その時は__download__内のログの内容とか教えてください(ユーザーIDやパスワードとかは消しておいてね!)。

なんか「変換エラー」が出るんだけど…

 __download__フォルダの中身を全部消してみてね。

ニコニコ動画がアップデートして動画がDLできなくなったんだけど…

 上記でも報告を受け付けてますが、Pythonに詳しい場合はext\SaccubusFront内のスクリプトを書き換えても対処できます。対処したらパッチにしてぜひ投稿してくださいね!

「***」っていう機能ないの?

 バグと同じところで受け付けてます。でもせっかくだから一緒に開発しましょう!! もちろん新機能パッチの投稿もウェルカムです†1

なんかアンチウイルスソフトが反応するんだけど

 「『ffmpegを起動する』バッチファイルを生成して起動」する、という二段構えの形式のため、反応するようです。「さきゅばす」が信用できると思う場合は切ってから実行してみてください。

というわけで私はしばらくこもる

 他にやらなきゃいけない事があるのに随分これに時間を費やしちゃったので、バグとかあってもしばらく対応できません。すいません。その時は2chで配ってる旧バージョン使ってね!!!

  • †1: 私の独断でリファクタの可能性や激しい変更の場合は一時保留の可能性もあります、ご了承下さい…。

昨日超会議で話した時のスライドをうpしておきます

Posted on

昨日の超会議ニコニコ学会βはお疲れさまでした。なんか顎のあたりが青々としててすいませんまだタイムシフトは誰でも見れるらしいですよ!

タイムシフトで見てたら「あとでうpお願いね」って書いてあったのでうpしておきます!

[全画面/表示されない場合]

なお、さきゅばすへのパッチ受付などはメールの他、公式サイトのチケット一覧などに投げていただいても対処できます。

あとサポートを2ちゃんスレッドに投げといて言うのも憚られるものがあるのですが、2ちゃんねるはISP規制のせいで書けないです、ごめんなさい…(一応読んでます)。

5月下旬まではあんまり開発できない感じです。。。あとはGUIのラッパーがあればなんとかって感じなんですが…んー。ニワン語の仕様書起こしとかソースコードガイドとかも書きたい…。


明日話す「さきゅばす2.0」、α版のソースコードを公開しました

Posted on

 昨日宣言したので、一応公開します!超会議の準備があるので、ちょっと説明を書いてる暇はなさそうですorz

 明日、ニコニコ超会議内の「第二回ニコニコ学会β」の1コーナー、「コメントアートセッション」にて、このプログラムについてお話します。

 なお、ライセンスはGPLv3です。

Saccubus

 本体です。ffmpegのフィルタとして動作し、コメントを実際に動画に焼き込みます。C++製。

git clone git://git.sourceforge.jp/gitroot/saccubus/Saccubus.git

SaccubusFront

 GUIなどを備えるフロントエンドです…と言いたいところですが、まだありません。現状では上のさきゅばす本体から呼ばれて、動画やコメントのダウンロードなどを行なっています。Pythonです。

git clone git://git.sourceforge.jp/gitroot/saccubus/SaccubusFront.git

Nekomata – The Open Niwango

 ニコニコ動画で使える特殊な言語「ニワン語」のフリーでオープンな実装です。C++製です。

git clone git://git.sourceforge.jp/gitroot/saccubus/Nekomata.git

 いよいよ明日です、正直なんだかドキドキしてきました。。。おて柔らかに、お願いしますm(_ _)m


今度の日曜日「ニコニコ学会β」で話します!

Posted on

 こんにちは!

 ついに明日からニコニコ超会議ですね!

 今回、このニコニコ超会議内で開催される、第二回ニコニコ学会βで登壇者として話すことになりましたので、唐突ですがお知らせします!

さきゅばす2.0

 5年くらい前に作って割りと放置してた、ニコニコ動画コメント付き動画保存ソフト「さきゅばす」ですが、今回、1からC++とPythonで書き直し、ニワン語ニコスクリプトにも対応したバージョンを作成しました。

 ニワン語はニコニコ動画で動く特殊なスクリプト言語で、ニコ動で動く音ゲーLispインタプリタなどの「謎の技術」の謎を支えています。

 比較動画はこちら。どうしても重くなりがちな「謎の技術」動画も、変換してしまえばサクサクと見れてしまいます。

 また、このプレイヤでは、1フレームずつコマ送りにしながら操作しつつ変換が出来るため…TASも作れます!

 この新しいさきゅばすについて、紹介と技術的な話ができたらな~と思ってます。

「コメントアート」セッションにてお話します!

 二日目(日曜日)の12:50から行われる、「コメントアート」セッション内でお話することになっています。生放送もやるそうなので、当日これない方もぜひ!アレげな格好するから生放送のが細かいところが見えなくて都合がいい

 私はソフトウェア技術の話をしますが、セッション全体としてはニコニコ動画の「コメントアート」がメインです。原稿の下書きを見せて頂いたのですが…凄まじいですよ…!コメントってこんなに進化してたんですね~。

ソースコードは明日公開。

 ちょっとまだバイナリ配布できるようなUIなどが未実装なのですが、ニワン語のインタプリタ「ねこまた」と動画変換部分のコアについて、明日、ソースコードを公開します。


C言語標準ビルトイン型で関数オーバーロードしてはいけない

Posted on

可変長引数とva_listでオーバーロードしてみた

 Cの標準関数には、可変長引数を取るsprintfと、その引数をva_listで受け取るvsprintfの2つがあります

int snprintf(char *str, size_t size, const char *format, ...);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);

 Cにはオーバーロードの仕組みがありませんから、引数の渡し方が違うだけの関数の名前が変わってしまうのもやむなしです。でも、C++ならオーバーロードをサポートしていますから、これらをこんな感じで一緒にできたら嬉しいな~と思いました。

std::string format(const std::string& format, ...);
std::string format(const std::string& format, va_list ap);

 が、しかし。このオーバーロードは64bit環境でのみ、*たまたま*うまく行きますが、32bit環境では失敗します。

 サンプルを使ってしらべましょう

#include <string>
#include <cstdarg>
#include <cstdio>


std::string format(const std::string& format, ...)
{
	printf("FORMAT 1 CALLED\n");
	return ""; /* サンプルなので未実装 */
}
std::string format(const std::string& format, va_list ap)
{
	printf("FORMAT 2 CALLED\n");
	return ""; /* サンプルなので未実装 */
}

int main(){
	va_list list;
	
	format("format: %s", "Hey!");

	return 0;
}

 さて、main内でのformat呼び出しに注目してください。第二引き数はconst char*なので、最初の可変長引数の関数が呼ばれるのを期待したいところです。

 実際、Fedora 16 x64(gcc 4.6.3)でビルドして実行すると

% ./test 
FORMAT 1 CALLED

 パチパチパチ。

 ところがしかし。Windows Vista32bitのMinGW(gcc 4.6.1)やUbuntu 11.04 32bit(gcc 4.5.2)で同じものをビルドすると…。

$ ./test.exe
FORMAT 2 CALLED

 後者が呼ばれてしまいます…な、なんで…?

ビルトイン型の実際の型を調べるには?

 オーバーロードがうまくいっている、という前提で考えて有り得そうなのは、va_listの実際の型が違う…のかもしれません。

 というわけで、調べてみましょう。g++のEオプションを用いると、プリプロセッサをすべて展開できます。

$ g++ -E test.cpp | grep typedef | grep va_list
typedef __builtin_va_list __gnuc_va_list;
typedef __gnuc_va_list va_list;

 むむむ、ヘッダファイルだけでは解決できませんね…。

 そこで、gdbの出番です。ptypeというコマンドを使うことで、実際の型を調べることができます。

 まずは、Fedora 16 64bitでやってみます。

% gdb test 
(gdb) break main
(gdb) run <- mainの一番上でストップします
(gdb) n <- 一行進めないと、スタック上にlistが定義されない
FORMAT 1 CALLED
22		return 0;
(gdb) ptype list <- main関数で定義されているva_list list;の定義を調べる
type = struct typedef __va_list_tag __va_list_tag {
    unsigned int gp_offset;
    unsigned int fp_offset;
    void *overflow_arg_area;
    void *reg_save_area;
} [1]

 というわけで、何かよくわかりませんが、va_listは構造体らしいです。なるほど、それならちゃんと可変長引数の方が呼ばれるのは納得です。

 64bit環境では構造体なら、32bit Windowsだと…。

(gdb) ptype list
type = char *

 期待通り!va_listの本当の型はchar*でした。だからオーバーロードでchar*を渡したらこっちが呼ばれてしまったんですね。

 これらの違いはなぜ起きるのでしょうか?

 おそらく、64ビットと32ビットでの呼出規約の違いに依るのだと思います。32bitのgccでは、引数をすべてスタック上(=アドレスがある)に格納されるため、va_listは単純なchar*で良いのですが、64bitのGCCでは基本的にレジスタ上に置くため、上記のように構造体で管理しているのでしょう。

 こういった事がありますから、型が明確でない場合はオーバーロードに使うのはやめたほうが良いですね…。

Visual Studio 2010だとどうなんのさ?

 同じリポジトリ内に入れておきました。私は32bit版windowsしかないので、そちらで試したところ、

20110325.png

 …どうやら、同じみたいです…。64bit版は知らないので、誰か試したら教えてね。


達人プログラマー:10年前の最先端と今の普通

Posted on

一部では有名?な「達人プログラマ」を、大学の図書館で見つけたので読んでみました。

職業プログラマ向けの啓蒙書、と言ったところ。純粋なプログラミングの話だけでなく、お客さんや同僚と一緒に仕事をしていく事に関してや、(私の好きではない)人生論っぽいところもあります。

で、ぶっちゃけなのですが、2012年となった今、特に読まなくて良いと思います

10年前の最先端は、今の普通になった

読んでもしょうもない、くだらない内容が書いてあるというわけではなくて、もはや今すでに十分浸透していて、インターネットで当然のように言われてる内容が多いからです。

「ソフトウェアの直行性」、つまり「ソフトウェアの一部は他の部分と独立してるべき」というのは本当によく言われてることですし、「DRY(Don’t Repeat Yourself)」も、Ruby on Railsという有名かつ優秀なサンプルがあります。本で自然言語で読まなくても、コードを書きながらDRYってどういう事なのか、理解してる方は多いのでは。「テスト駆動開発」もどこかで聞かれた事があるでしょう。

奥付をめくってみると、2000年11月の出版でした。ITバブルとか、あの頃です。20世紀です。もう11年以上経っています。当時はきっと最先端だったのでしょうが、今は十分に浸透した考えばかりです。11年前の本でわざわざ読むより、インターネットで検索して、実例をたくさん見たり、いろいろな人の意見を検索して調べていった方が、きっと新鮮で刺激的で、何より「Pragmatic†1」な情報が手に入ると思います。

エディタの紹介も、Brief(DOSのエディタ!)だったり、ソースコード管理システムの例がCVSやらSCCSだったり…2000年はSVNがやっと出来た頃(!)なので、すごーく隔世を感じます。ITバブルでどっと混むでIT革命†2な、あの頃へ戻るタイムマシンに乗るような楽しさは有るかも知れませんね。

10年前は最先端だったけど、今でもそんなに…

表明プログラミングEiffleSatherアスペクト指向プログラミングは未だにメジャーでは無いですね…。このあたりは読んでいて面白かったです。

あと「どこでもいつでも何でも自動化」というコンセプトは、理解はされてても、まだそこまでメジャーじゃないきがします(私の周りだけかな?)。確かに自分でスクリプトを書いて自動化すると楽なのですけど、最初書くのが結構おっくうなんですよね…。もっと楽に自動化できるようなツール出来ないかなー!

  • †1: 原題:Pragmatic Programmer
  • †2: 本当に聞かなくなったワードばっかり!