「JSONP」を含む日記 RSS

はてなキーワード: JSONPとは

2020-06-20

anond:20200616084705

JSONP エフエム東京の「毛」というCMが賞を受賞してるようだが…

から

misozui 「ハーフの子を産みたい方に」を思い出した

これって

銀座いせよしポスター東京コピーライタークラブ新人賞で入選

みたいな話だな

2017-03-09

http://anond.hatelabo.jp/20170309042831

この話は、途中で「危ない」の意味がすり替わっているので混乱してるんじゃないかな?

1. クロスドメイン制約で他ドメインサーバリクエスト投げられません ← わかる

これが許可された場合攻撃危険性にさらされるのは「リクエストを受ける側」のサーバだ。

この場合攻撃である可能性を持つ「リクエストを投げる側」は不特定多数である

2. <script src="">なら他ドメインも取れるよ ← まあわかる

3. じゃあここを動的に変えて、実体スクリプトファイル(JSONP)で関数呼んでデータ貰おう ←!?

ただのJSONだったころよりもっとあぶねーじゃん?

関数実行しちゃってんだぜ?

これが許可された場合攻撃危険性にさらされるのは「リクエストを投げる側」であり、先ほどとは攻撃者と被攻撃者が逆転している。

この場合攻撃である可能性を持つ「リクエストを受ける側」は、「リクエストを投げる側」が明示的に指定したサーバだ。

この問題は信用できないドメインに対して自分からリクエストを送らないようにする、という明確な対策可能である

JSONPは、「リクエストを受ける側」にとってXMLHttpRequestWebAPIを叩かれるよりも安全からドメインを超えた通信が出来るわけ。

まりこういうことね。

XMLHttpRequest危険性 (実際にはこの動作禁止されている)】
ブラウザ←ーーー「攻撃WEBサーバ」(悪意あるリクエストを投げるコードブラウザに渡す)
    ーーー→「被攻撃WEBサーバ」
        (悪意あるリクエストに答えてしまう)

【JSONP危険性】
ブラウザ←ーーー「WEBサーバ」(攻撃WEBサーバリクエストを投げるコードブラウザに渡す。※このサーバは、攻撃WEBサーバに悪意があることを知らない)
    ーーー→「攻撃WEBサーバ」(レスポンスとして悪意あるコードブラウザに渡す)
ブラウザ←ーーー
(悪意あるコードを実行してしまう)

JSONPなんて考えてるやつは頭おかし

1. クロスドメイン制約で他ドメインサーバリクエスト投げられません ← わかる

2. <script src="">なら他ドメインも取れるよ ← まあわかる

3. じゃあここを動的に変えて、実体スクリプトファイル(JSONP)で関数呼んでデータ貰おう ←!?

なんでそうなるの?

ただのJSONだったころよりもっとあぶねーじゃん?

関数実行しちゃってんだぜ?

リクエストだってドメインに飛んじゃってるし、クロスドメイン制約とかなんだったの?って話なんだけど・・・大丈夫か?

2017-01-20

[]1月20日

○朝食:なし

○昼食:ブリトー(餅お好み焼き)、ホルモン弁当

○夕食:キムチラーメンビールつくね

調子

はややー。

今日と昨日と遅くまで残業して疲れたからか、普段より一際、酔いが回っているので、変なこと書くかも。

問題ありそうならあとで修正する。

昨日言われた通り、調査っていうか、っていうか、向こうの人が望む方式でやるために、もう一度調べ直しをしてた。

向こうの人曰く「このやり方でできる」そうなんだけど、やっぱりどう考えても、できないようにしか思えない。

その、それなりにプログラマやってきてるけど、Web仕事はこの現場が初めてで、いやまあ一年ぐらいこのプロジェクトはいものの、今までは画面とかサーバーサイドで単体で動くバックエンドの仕組みとかを作ってたから、ちょっとこういう部分わからいか

はーい、と頷いて、頑張って調べたんだけど、

やっぱりどうも、そんなやり方はできないようにしか思えない……

うーむ、ちょっと、真面目に勉強したいな、本とか買ってまずは一般論を学ぶべきな気がしてきた。

っていうかあれか、クソ雑魚ナメクジらしく質問サイト質問すればいいのかなあ。

うーーーーーーーーん、なんか難しいなあ、

いやでも、なんか、仕組みを考える限り、できないようにしか思えないけどなあ。

でも、ネット調べるとやってる人もいるんだよなあ。

でも、なんでできるんだあ? なんか理屈がよくわからんぞいやだなあ。

だってさ、GETからURLの中に戻り値が入って取り出せるんでしょ?(うーーーーん、この理解もだいぶあやしいぞ、なんかうまくこの仕組みを理解できてない気がする) POSTだったら、戻り値レスポンス(あれ? リクエスト? いっつも、レスポンスリクエストがどっちかわからなくなる)のボディに入ってくるから、それただの戻り値で、JSONPでもなんでもなくない?

POSTのJSONPなんてできなくない?

でも、できるっていうんだもんなー。

よくわかんねーなー。

僕の頭が悪いんだろうなあ。

そもそも、なんで、向こうの人がPOSTに固執してるのかも、全く全然からないんだよなあ。

セキリティってなに? パスワードとか、機密事項ならわかるけど、ただの検索だしなあ。

しかも、検索結果は嫌がおうにも、DBテキストファイルログ出力されるから、誰が何を検索たかは、URL覗けるぐらいの人なら、POSTでもわかると思うんだけどなあ)

あーーーーー、ビールおいしい。

●XboxOne

○HaloWars2

マルチプレイオープンベータが始まったので、とりあえずダウンロードだけした。

ストーリーが楽しみで、対人戦はあまり興味がなかったんだけど、ネットインタビュー記事によると、

5分とかそれぐらいで楽しめる、短めのモードがあるらしいので、少し興味がある。

別にこれが楽しくなくても、ゲーム自体は買うんだけどね。

3DS

すれちがいMii広場

プレイ

今日10人フルにすれ違えたので、どれも進んだ。

バッジとれ〜るセンター

アクジキングに、ジョウトの悪ポケたちがキターーーー!!!

というわけで、速攻で課金課金

ちゃんと、全員揃えて、悪ポケを並べて満悦です!

恒例の、悪ポケモン実装リスト更新です!

「両」は普通絵、ドット絵共に実装済

「普」は普通絵のみ実装済

「ド」はドット絵のみ実装済

「未」はドット絵でも普通絵でも未実装

カントー

コラッタ(両)、ラッタ(両)、アローラコラッタ(普)、アローララッタ(普)

ニャース(両)、ペルシアン(両)、アローラニャース(普)、アローラペルシアン(普)

コイキング(両)、ギャラドス(両)、メガギャラドス(普)

イーブイ(両)

ベトベター(ド)、ベトベトン(ド)、アローベトベター(普)、アローベトベトン(普)

ジョウト

ブラッキー(ド)

ヤミカラス(両)

ニューラ(両)

デルビル(両)、ヘルガー(両)、メガヘルガー(普)

ヨーギラス(両)、サナギラス(両)、バンギラス(両)、メガバンギラス(普)

ホウエン

ポチエナ(ド)、グラエナ(ド)

タネボー(両)、コノハナ(両)、ダーテング(両)

ヤミラミ(両)、メガヤミラミ(普)

キバニア(ド)、サメハダー(ド)、メガサメハダー(普)

サボネア(両)、ノクタス(両)

ヘイガニ(両)、シザリガー(両)

アブソル(両)、メガアブソル(普)

シンオウ

ドンカラス(普)

スカンプー(普)、スカタンク(普)

ミカルゲ(普)

スコルピ(普)、ドラピオン(普)

マニューラ(普)

ダークライ(未)

例外:無アルセウス(普)、悪アルセウス(未))

・イッシュ

チョロネコ(普)、レパルダス(普)

メグロコ(普)、ワルビル(普)、ワルビアル(普)

ズルッグ(普)、ズルズキン(普)

ゾロア(普)、ゾロアーク(普)

コマタナ(普)、キリキザン(普)

バルチャイ(普)、バルジーナ(普)

モノズ(普)、ジヘッド(普)、サザンドラ(普)

・カロス

ケロマツ(両)、ゲコガシラ(両)、ゲッコウガ(両)、サトシゲッコウガ(普)

ヤンチャム(両)、ゴロンダ(両)

マーイーカ(両)、カラマネロ(両)

イベルタル(両)

戒めフーパー(ド)、解き放たれしフーパ(未)

アロー

ニャビー(普)、ニャヒート(普)、ガオガエン(普)

アクジキング(未)

例外タイプヌル(普)、無シルヴァディ(普)、悪シルヴァディ(未))

これで、アローラの悪ポケの普通バッジコンプ

僕は普通バッジを優先で集めてるので、

カントーは、ベトベターリージョンじゃない方)、ベトベトンリージョンじゃない方)の普通絵が未実装ドット絵はあるから仮置き中。

ジョウトは、ブラッキー普通絵が未実装ドット絵はあるから仮置き中。

ホウエンは、ポチエナグラエナキバニアサメハダー、の普通絵が未実装ドット絵はあるから仮置き中。

シンオウは、ダークライが両方未実装。仕方ないから、バッジとれ〜るセンターバイトを仮置き中。

イッシュは、普通コンプリート

カロスは、いましめフーパ普通絵が未実装ドット絵はあるから仮置き中。ときはなフーパは両方未実装。仕方ないから、バッジとれ〜るセンターバイトを仮置き中。

アローラは、普通コンプリート

こんな感じなので、仮置きしてる、ドット絵普通絵もない、悪ポケは、

ダークライと、ときはなフーパの二体のみ!

(悪アルセウスと悪シルヴァディ例外

うーむ、全悪ポケが揃うのがとっても楽しみです!

っていうか、もう、バッジケースがいっぱいいっぱいなので、ドット絵を外させてほしいから、早く普通絵でコンプしてほしいなあ。

ポケとる

セレビィレベル50)

目標を達成して、メガスキルアップをゲット。

これで、19個なので、目標20個まであと一つ。

20個揃えることで、レックウザが真の力を解放して、ようやく、ポケとるチュートリアルが終わる、とかネットコミュニティでは言われているので、楽しみ。

はいえ、コインを使えば、普通に真の力は解放できるので、コインが使えないランキングイベントとか、メインステージの道中とかで使うぐらいなのかなあ、まだよくわかんないや。

iPhone

ポケモンコマスター

ログボのみ。

2014-08-21

普段からいい人面してるブロガー達がデブ馬鹿にしてて怖い

このブクマ

http://b.hatena.ne.jp/entry/horahareta13.hatenablog.com/entry/2014/08/20/204033

普段人権関係エントリーにはえらそーな面で傷つく人もいるんですって感じのコメントつけてる面々がデブ散々バカにしてて胸糞悪い

外見でばかにするなとか病気ばかにするなとか言ってるくせにデブは無条件でクソデブワロスかよ

あんな、薬とか病気で太ってるのもおるんだけど

好きで太っとるんじゃないんだけど

追記

このブコメでもデブ叩くやつ出てくるじゃん、これが現実

id:ente04 漫画キャラから突っ込んでいいとか池沼発言批判されていや池と沼ですよって言うのと同じ詭弁ですね

id:JSONP 太ってる人は自己抑制がなっていないから馬鹿にしていいと思っている人もいるからね、そうでない人もいるという意味

2014-08-20

"痴漢妄想"の根源には、親による禁止令がある

http://anond.hatelabo.jp/20140820015153

 

強くあらねばならないと思っている人は、自分自身主体的な欲求や感情存在を認められないんですよ。

欲求は、相手に知られると足元を見られるウィークポイントでもあります。だから存在してはならない」。

他人にはあっても、自分には無いのが欲求や感情…という歪んだ認知をしてしまうわけです。

 

このタイプの人は「(私は)あいつを見ているとイライラする」ではなく、「あいつにはイライラさせられる」という言い方をしたり、

「私は面白いと感じた」ではなく「あれは面白い」と、原因を外部化して語ります

私はこうしたい・私はこう感じたという部分を、存在しないことにしようとしてるんですね。

から性欲についても「私は欲情した」ではなく「あいつに欲情させられた」、

まりは「あいつが誘ってきた」というふうに認知が捻じ曲げられます

その結果「痴漢!」と拒絶されると、本気でビックリして「裏切られた・騙された・ハメられた」と激怒してしまうんです。

 

こうした認知のゆがみというのは、個々人の「こうしたい」や「こう感じる」が邪魔組織にとっては便利な特徴です。

から社会的地位が高いのに痴漢」が発生します。

外野から見ると「せっかく社会的評価を得られたのに、どうして痴漢台無しにするんだろう?勿体ない…」と感じるところでしょうが

そもそも「私は強くあらねばならない」と強固に思っている人は大組織適応やすく、性格的に出世やすいんです。

(このタイプ性格なのに出世しないという人は、職能が無いとか、発達障害があるとか、別に問題を抱えているのでしょう)

 

女性から見て「私は強くあらねばならない」を抱えた男性が、配偶者として魅力的にうつるという問題もあります

子供が溺れるなどの家族の危機的状況において、父親に英雄的な行動を"とらせる"のも「私は強くあらねばならない」だからです。

自分がどうしたいか、どう感じるかではなく、「弱い者が助けを求めているから私が助けるしかないのだ」という状況は、

自分の行動の理由を外部化したがる性格の人にとって、好ましいものになります

ヒーローものが全世界的にウケるのも、それだけそういう男性と、そういう男性を好む女性が多いことの証左でしょう。

 

こうした歪みを改善するには、自分の欲求や感情存在を、自分自身で認めることが重要です。

欲求や感情は「あっても良いもの」です。親に「泣くな!」「欲しがるな!」などと、欲求や感情を禁止されて育った結果、

親を内面化した大人になってしまうのですが、そうした禁止令を解くことです。

そうすれば「あの女に、尻を触りたいと思わされた」ではなく、「私はあの女の尻を触りたいと思った」と正確な認識ができるようになります

それは欲求に責任を持つと同時に、主体性を取り戻すことでもあると思います

 

skgctom

金色夜叉の像みたいな男女関係(ヤレヤレ系)を理想化してる人結構いるよなと思う。

無根拠な自尊心の高さ由来かと思ってたけど、抑圧の結果と考えると確かに頷ける

ヤレヤレ系の物語に固執する人は自尊心が低いと思いますよ。

自尊心が低いからこそ防衛しようとして、恋愛への欲求を外部化・他責にした結果がヤレヤレ系。

恋愛への欲求が無い人は、恋愛描写が出てこない物語を好みます

 

gazi4

子育てで似た論理はあるし、認知の歪みも理解できる。が、この話では「最初にしてしまう」理由が分からない。

さな子供論理的思考が出来ないため、ちょっとしたことで認知がゆがむように出来ているんです。

つの例で「みんなそうだ!」「いっつもこうなる!」と思いこんでしまます

大人になる過程で、そうした歪みが論理的思考によって改善される人も居れば、

歪んだ認知を補強する事例ばかりを執拗に集めて、犯罪者になってしまう人も居ます

その差は遺伝と環境の複合によって生まれると思います

 

JSONP

最近何でも親の育て方のせいにする風潮あるけど、何なのこれ?

原因は親にありますが、完璧な親など居ませんし、親が成人した子供責任をとることは出来ないので、

自分認知のゆがみを解決しなければならないのは本人だと考えています

健康な大人の脳みそなら、本来可能なはずなんです。

これまで通りに自分を騙し、好みの認知の歪みに逃げ込むほうが楽なので、大半の人はそれを続けるだろうというだけです。

性犯罪者に至っては、何度捕まっても続けるでしょう。

2013-08-13

PC遠隔操作事件】ラストメッセージ全文(転載

元記事が消えた時のために転載。

【PC遠隔操作事件】「真犯人」からのラストメッセージ(江川 紹子) - 個人 - Yahoo!ニュース

http://bylines.news.yahoo.co.jp/egawashoko/20130810-00027167/

■はじめに
お疲れ様でした。
冬山はいかがでしたか?
私は紅葉のはじめの頃に行ったので快適でしたが、雪が積もった山は大変だったと思います。

さて、これまでメールにてさまざまな質問が寄せられました。
関連報道で謎とされている部分もあります。
それらについてFAQ形式でお答えしたいと思います。

■なぜこうしたことをなさったのですか 警察・検察にどんな恨みがあったの?動機について詳しく教えて。
私もまた、間違った刑事司法システム被害者です。
ある事件に巻き込まれたせいで、無実にもかかわらず人生の大幅な軌道修正をさせられた人間です。
それがどんな事件だったのかは詳しくは言えません。
サイバー関係ではありませんが、彼らが間違いを犯した原因の趣旨は、その事件も今度の事件も大して変わりは無いものです。
刑事司法の問題点として良く出てくるキーワード、「自白偏重」「代用監獄」「人質司法」「密室取調」「作文調書」...etc
私はそれらを実体験をもって知る人間です。

そして、そのとき私は負けてしまった。やってないのに認めてしまった。
起訴された。公判で「反省している」と発言した。
おかげで刑務所に行かずに済んだが、人生と精神に回復不能な大きな傷を残した。

一連の事件は、私が「負け犬」から復帰するためのリベンジと言えます。
『先に償いをさせられた人間はその分の犯罪を犯してもいい』という持論。
あなたは間違っている、たとえどんな理由があっても許されない、そういう突っ込みがあることを理解する程度の理性はあります。
でも、それが私だけの哲学であり、誰にも軌道修正されない行動原理です。
いつかのDigで誰かが「犯人は壊れている」と表現していました。
そう、壊れている。私を壊したのは奴らだから。

■警察・検察をナメてるの?
慇懃無礼な文面から「ナメている」「グリコ森永事件みたいだ」などと言われてますが、そんなことはありません。逆です。
警察・検察の怖さは思い知っています。
どれほど怖いか、どれほどしつこいかを。
それを知っているからこそ、ここまで神経症・偏執狂とも言えるまでに厳重な注意を払って動いてきました。
ほとんどの人は、それだけの体験をしたなら、「もう警察には逆らってはいけないのだ」「目をつけられないようコソコソ生きよう」そういう卑屈な人生を送るのでしょう。
しかし私はその気持ちのベクトルが逆に働きました。
恐ろしい警察・検察に挑戦し、乗り越えることこそが私の人生に課せられた試練であり、それ無くしては一生負け犬として生きていくしかないと思いました。

■自殺予告について。
・ミス
「ミス」は嘘です。ごめんなさい。自殺する気は全く無かったです。
11月10日前後に、どこかの記事で「犯人が致命的なミスか?」「Torを使わず直接書き込んだ箇所」というのが載ったのがきっかけです。
決定的なミスで警察も期待しているかのような報道だったゆえ、ちょっと乗せられてみました。
結論を言うとその書き込みもTorです。
Torに割り当てられる出口ノードによっては2ch書き込み可能なところもあります。
たまたまそのとき書けるところに当たったので、わざわざシベリアの依頼スレを使わなかったというだけの話です。
結局何だったのかというと、一部メディアが言っていた「観測気球」という表現が半分合っていて、あとの半分は「面白半分」です。

・新聞紙予告犯」という漫画を読んで、とても共感を覚えました。
特に、登場人物の犯人グループの一人であるゲイツ」君の境遇には自分と重ね合わせできるものがありました。(11月に入ってからはじめて単行本で読んだので、このマンガに感化されて一連の事件を起こしたというわけではありません。念のため)
その作品に出てきた、新聞紙を使う手口をちょっとだけ真似てみたというわけです。

・写真位置情報
恥ずかしいことに、これは本当にミスしました。
保土ヶ谷の適当な住宅地の緯度経度を入れたつもりが、10進数→60進数の変換を忘れてしまいました。
これは本当に私の無知であり、ラックの西本さんに「犯人は教養がない」と言われても仕方ありませんねw
結果的には、保土ヶ谷の団地が捜索され、意図どおりにはなりましたが。

■決して死を選ばす、生きてすべての真実を明らかにしてください。
死を選ぶつもりはありませんが、自首することもありません。
もし仮に捕まったとして、私が白旗を掲げて自白したとしたなら、動機について「逆恨み」と表現されることでしょう。
「前科者が前に捕まったことを逆恨みしてまた犯罪を犯した」と、報道各社は警察発表そのままに垂れ流すでしょう。
私が前に経験した事件の判決が覆ることも無いでしょう。
もっと掘り下げてくれるほどマスメディアの皆さんのジャーナリズムを信用していません。
記者クラブで警察とベッタリなのは分かっているから。
「真実を明らかに」という点ではこのドキュメントだけでも十分なのではないですか?
これだけ詳細に書いたなら、あと残りの謎なんて、私の住所氏名年齢程度の些細なことでしょう。
そんなことで事件の全容が変化するわけでもないです。

■ご本人について・・・お名前、性別、年齢など可能な限り、ご本人様について教えてください。
ご想像にまかせます

■取材させてください
できません。
このドキュメントを持って、私から発信すべきことはもうありません。

余談になります。基本的に面会取材は一切受けるつもりは無かったのですが、英国のBBCの方から取材依頼のメールが来たとき、ちょっとだけ気持ちが動きました。
以前見た「ポチの告白」という映画を思い出したのです。
警察腐敗、刑事司法の問題、記者クラブ制度の病巣、そういう部分を明らかにした、社会派な内容です。
登場人物が警察腐敗を暴こうとするも、記者クラブ制度に漬かった国内メディアには全く相手にされず、普段記者クラブから締め出されている海外メディアを頼るシーンが出てきます。
そのシーンを思い出し、BBCの取材依頼なら受けてもいいかな?と傾きましたが、やっぱり止めました。
そこまで出しゃばり屋でもないし、「凄腕ハッカー」のような扱いで出されても困る。(そこまで誇れる技術力があるつもりもない。)
「刑事司法の問題」という部分で言いたいことはいくらでもあるとは言え、私程度が言えることは誰かもっと頭のいい専門家が既に言っています。
だからわざわざ出る必要も無いと思い、他のメディアと同じようにBBCのメールも無視しました。
落合洋司先生がBBCの取材を受けていたようなので、それで私が言いたいこと、世界に向けて言うべきことは言ってくれたと思います。多分。

■どんなことを考えていますか?世間の反応についてどう思いますか?
警察が誤認逮捕をやらかす、世間が騒ぐ、という意図どおりの結果になったとは言え、反響が予想以上に大きく戸惑っています。
同時に達成感も大きいものとなっています。
正直なところ、もともと犯行動機は私怨が主で、あまり政治的自己主張は考えていませんでした。
警察・検察・世間が騒いであたふたしたら嬉しいな、自分の溜飲が下がる、それだけでした。
「刑事司法の矛盾を暴く」というような高尚な目的意識も高くはありませんでした。
また、神保哲生さんが、「ダウンロード刑罰化・ACTA・サイバー犯罪条約児童ポルノ単純所持処罰などのネット規制の動向に抗議する意図も犯人にはあったのではないか?」のように分析していましたが、そのあたりについても全く考えていませんでした。
それらについては、事後に専門家コメントを見て深く考えるようになりました。
もともとネット規制は私もどちらかというと大反対です。
刑事司法の諸問題、ネット規制に関する諸問題、どちらについても国民の自由が奪われる方向に向かっていくことは防がないといけないと思っています。
後付けの動機となってしまいますが、今となって思えば、自分の行為がその一助になれたら本望です。
(もっとネット規制のほうは私のせいで逆に締め付けが強くなりそうですが)

余談です。
家電量販店ウイルス対策ソフトのコーナーでは、「遠隔操作ウイルスの脅威」のように煽るPOPを付けて売っていますね。
私はそういうところに立ち寄り、一連の事件の社会的影響を確認したりしています。
売り場に立っているソフトメーカーの販促スタッフに、ぱそこんしょしんしゃの振りをして神妙な顔で、「最近ニュースで話題の遠隔操作ウイルスがすっごく不安なんです(>_<)」のように話しかけてみました。
すると「この製品が一番最初にiesysに対応したんですよ!」と、とても嬉しそうにアピールされました。
何だかおかしかったです。
今まさに目の前に真犯人がいるとはこの人は微塵も思ってないんだろうな・・・と内心考えながら、説明をしっかり聞いてあげました。

■目的通りに誤認逮捕を招き、警察・検察が謝罪しているが、今どのように感じているか
警察官検察官もっと人並みに、人の話をちゃんと聞く姿勢があれば1件も誤認逮捕など起こさなかったのでは?と。
あの人たちはコミュニケーション能力以前の問題、日本語というか地球語が通じない宇宙人です。
彼らにそういう能力が無いことを分かっていて試した私も私ですが。
結合試験のテストパターンを作って流したら再現性のあるバグの結果が得られた、そんな感想です。
テスト結果を全国に、全世界に提示できたことは大変有意義だと思います。

■警察の技術レベルについてどう思われたか
CSRFについては見破られると思っていました。
後述のようにいろいろ工夫したとは言え、「2秒で送信」問題は消せなかったので。
私の知っている警察のしつこさは、被疑者をシロにする方向には働かなかったのだなと再確認。

iesysについては見つけられなくても仕方が無いです。
投入前に、主要なウイルス対策ソフト体験版をいくつか試用し、検知に引っかからないことを確認しました。
完全自作プログラムだったので定義ファイルパターンマッチすることは無いですが、ヒューリスティック検知に引っかかるかも?と興味を持ちテストしました。
特にキーロガー機能でOSのキーボードマウス入力命令をフックしているあたり、「怪しいプログラムアラートぐらい出てもおかしくないと推測。
結果的にはどの製品でも引っかかることはありませんでした。
あの手の「ヒューリスティック検知搭載」と謳って売っている製品が、それをどのような基準で行っているのか興味深いところですね。

警察の技術レベルが高いか低いかですが、今回の失態の趣旨は、デジタルとは関係ない部分での捜査手法の欠陥のほうが、原因の多くを占めていると思います。
技術レベルは高いところもあれば低いところもあるのでしょう。少なくともサイバー課をナメてはいないし油断してもいません。
140人の捜査体制だ、FBIに協力要請だ、そういうのを見て正直プレッシャーを感じてもいます。

最近の動向として、「犯人がアクセスした可能性のある90億ログを解析している」という。
これについては、直接関連するサイトへのアクセスは下見閲覧段階も含めて完全にTorを使っています。
たとえば横浜市サイトやJALのサイトなど、一度も生IPでアクセスしたことはありません。
この時点で9割5分、捜査線上に挙がることすら無いと思っています。

しかし全てのアクセスでTorを使ったわけではない。
間接的に関連するようなサイトは、普通に閲覧したところもあります。
ビッグデータ解析のようなことをして、「こいつはこのサイトとこのサイトを見ているので怪しい」という、
100人か200人かの「犯人候補」の中に絞り込まれることも無いとは言えないです。
全国津々浦々、それら犯人候補のところに一人ずつ家庭訪問すれば、どこかで私に突き当たるかもしれない。

その可能性も予測しているため、油断は一切していません。
前に述べたようなオンラインでのアクティビティだけではなく、自分しか触らないローカルPCの中身までも偏執的なまでに注意を払っています。
つまり、私のPCを調べたところで証拠は何も出ません。他の100人200人の犯人候補者と同様に。

犯行に使った罠Javascriptトロイソースファイルのものから、細かいメモに至るまで、ファイルを置く場所については厳重に管理していました。
そしてそれらが存在した記憶媒体、およびそれらを開いたことのあるシステム記憶媒体は全部、とっくに完全消去の後、スクラップにして燃えないゴミに出してしまいました。
現在うちにあるシステムや外部記憶媒体全部、どんな高度な復元やフォレンジックを行おうと関係ありそうなものは何も出ません。

令状なしで来ても「どうぞどうぞ」と見せてあげますよ。
エロ画像の10枚や20枚は普通にあるので、それだけ鑑賞してお帰り下さい(笑)

それとも、犯人候補の中からあてずっぽうに選んでお得意の自白強要しますか?
「真犯人」を追求したつもりが、「新犯人」を作ることにならないといいですね。
私は根っからのカタギであり、ヤクザ過激派セクトの人のような海千山千犯罪者ではないですが、経験者であるだけに、否認なり黙秘なり適切に対応する自信はありますよ。
「テメエコノヤロウ」とか、「お前の関係先にガサ入ってガチャガチャにしてやるからな!」(原文ママ)とか同じようなセリフを言われても今度は負けませんよ。

■一体、このゲームをどこまで続けるおつもりですか?どのように決着をつけるつもりでしょうか。
もうやめます。
私の気が済むまでやって捕まらなければ勝利、という条件を設定していましたが、ここまで反響が大きいと、私の溜飲は下がりました。もう負け犬ではないです。
私が巻き込まれた事件のことも、私が起こした事件のことも、全部忘れて再出発します。

■誤認逮捕された4人の男性への謝罪の気持ちはありませんか。
こうでもしないと警察・検察を自省させることはできなかった、仕方の無いこととは言え、大変申し訳ないと思っています。無関係の4人を巻き込んだこと、軽く考えてはいません。
自分は悪くないなどと言う気はないです。償わなければならない罪を犯したことは分かっています。
でもそれ相当の罰は先に受けている。だからこれ以上責任を負うつもりはないです。
罪と罰の因果の逆転。そういうことが起こっていることを分かってください。

■横浜事件
・●●小学校
横浜市サイト脆弱性があったのを見つけたので、横浜市小学校一覧から無作為に選んだだけです。

・「鬼殺銃蔵」の意味
「餓鬼殺し」を省略して「鬼殺」。また、日本酒の商品名とかけたというのも合ってます。
殺し屋であるゴルゴ13、「こち亀」に登場したパロディキャラ「後流悟十三」、あと昔読んだ「隣人13号」の主人公の「村崎十三」、そのあたりのキャラクターイメージし、「じゅうぞう」という読みに決め、「銃蔵」と当て字にして完成。
それほど深く考えて決めたわけでもない、30秒ぐらいで決めた名前です。

・本文
猟銃で射殺していく内容は、春ごろに読んだ小説「悪の教典」を参考にしました。

・CSRFについて補足説明
CSRFの仕組み自体はオーソドックスだったのですが、ちょっと工夫を入れました。
1)犠牲者は最初の一人のみに絞った
不特定多数が見る掲示板に貼るという性質上、複数の人が踏むのは当然。
そして複数の人から一字一句違わない脅迫文言が届いたら、どんなに警察がお馬鹿でも何らかの仕掛けを疑うでしょう。
サーバ側のPHPで制御することで、最初に踏んだ一人にのみ有害CSRFが発動し、2人目以降は無害なリダイレクトが発生するだけという仕組みになっていました。

2)キャッシュで罠スクリプトを発見されない工夫
A「直接踏ませるスクリプト。BをJSONPクロスドメイン読み込みして実行する」
B「CSRFを行う有害スクリプト。Aとは別サイトに設置。」
の2部構成。
Bの側に、1)で書いた制御を入れました。
そして、Aでは、
「Bを読み込んで変数に格納(B1)→Bを再度読み込む(B2)→B1を実行」
というフローで動作します。Bを2回読み込むというのが肝心です。1)の制御により、B1はCSRF、B2は無害スクリプトになります。
永続性記憶装置に保存されるブラウザキャッシュには、B1はB2に上書きされ、B2だけが残ります。
変数に格納されただけのB1は実行後、DRAMから揮発してしまいます。

ただし再読み込み時、キャッシュ再利用の挙動はブラウザごとに異なります。
IE等では、2回目の読み込みは発生せず、キャッシュから拾ってきてしまいます。(2回目もB1になる。)
URLの語尾にgetクエリユニーク文字列を付加するというのがキャッシュリサイクル対策の常套手段ですが、
これをするとどのブラウザでも全く別のURLとして扱われ、キャッシュも個別に残ってしまうのです。
解決方法が思い浮かばなかったので、Aの時点でダメブラウザ入り口で弾くようにしておきました。

3)エスケープ
一応気休めで、文言も含めたスクリプト全体を、encodeURI()関数でエスケープしてありました。
仮に有害スクリプトキャッシュが残ってしまっていたとしても、発見しづらくなる効果を狙いました。
その時刻付近のブラウザキャッシュに対し、脅迫文言の一部で機械的にgrep検索をかけたとしても、罠Javascriptの構文は引っかからないはずです。
もっとも2)がちゃんと機能していれば別に平文のままでも良かったのですが。一応念のためにという感じ。

4)iFrameにより関連サイト4~5箇所次々と読み込む
単に文言を送信させるだけなら、所定CGIにリクエストパラメータ付きでPOSTする仕組みで良かったのですが、
それだけではなく、「犯人性を高める」工作を入れました。
明大生のPCに小学校サイト等へのアクセス記録があったというのはこれのことです。
「小学校サイト」「横浜市トップページ」「入力フォームのページ」などを読み込ませることで、あたかも自分でアクセスしたようなブラウザログ・キャッシュが出来るのを狙ってのことです。
何の前触れも無くいきなりCGIだけを触った痕跡しかなかったとしたら、警察の捜査員が見ればどう考えても何らかの仕掛けを疑うと思ったため。
もっとも、開かれている数秒のあいだに全て終了させた以上、「2秒で250文字を送信」という不自然さは消せないわけですが。
数分のあいだ開かせ続けられるような魅力的コンテンツを用意できれば、時系列的にもっと自然な形で文言の送信ができたのですが。
まぁ面倒だったので、時間的不自然があることは把握しつつ、うまく行くかどうかはダメ元でのチャレンジでした。
警察がお馬鹿だったので見事に嵌ってくれたわけですが。

・「告白文」のゆくえ
上記のように、CSRFスクリプトをこれだけ工夫しすぎたせいで、ちょっと動作の不具合があったみたいです。
後で試したら、大丈夫だと思っていたブラウザでもうまくいかないことがあったり。
おそらく「告白文」のほうは、踏んだ人の環境では正常動作しなかったのだと思います。
逮捕2日目でネタバラシしたつもりが、発覚まで3カ月以上も費やさせてしまったことについて遺憾の意を表したいです。

7月初旬のあの時期、告白文は届いていたと思っていたのに「誤認逮捕」報道が無いことについて、警察が完全に黙殺したか、釈放はしたものの明大生に因果を含めて騒がないようにしたか、記者クラブでベッタリのマスコミに因果を含めて黙殺させたか、そっちの可能性で考えてしまっていました。

■CSRFとオリジナル遠隔操作ウイルスを作成しているが、途中切り替えたのはなぜか
CSRFでは、脆弱性のあるサイトにしか通用しないです。
それを探し出すのもまた手間なので。
もっとどんなサイトでも適用できる汎用性のある手段をと考えて、iesys.exeを設計しました。

■大阪
●●●氏へのお詫びに●●●のBDを全巻買いました。
今まで見たこと無かった作品でしたが、ファンになってしまいました。
新作映画も見に行きたいと思います。

■福岡
遠隔操作先PCオーナーは福岡の人だったと分かり、福岡ドームとか太宰府天満宮とかを脅迫する文言を書きかけたのですが、気が変わりました。
警視庁の方たちに、遠路はるばる福岡までガサ入れしに行かせてあげるのも一興かなと思い、わざと東京のターゲットにしました。
単純に警察に対する嫌がらせです。
(せっかくだから稚内とか利尻島とかも思いついたんですが、さすがに僻地すぎて無視されるだろうな・・・と思ってやめました。)

■三重-「わざと消さなかった」は虚偽では?
最初の感染確認後すぐ遠隔操作で2chに伊勢神宮脅迫書き込みを行い、その後しばらくPCの中身を物色していたのですが、
iesysのキープアライブ通信が途絶え、オフラインになってしまいました。
単にオーナーが電源オフにしたのかと思い、自分でプロセス停止をしたことまでは分かりませんでしたが。

したらばのスレッドsuicaコマンドさえ書き込んでおけば、次にオンラインになったときに勝手に消える仕組みですが、このときはそれはしませんでした。

このPCが捜索された際、ひょっとしたら警察の捜査の実行画面が見られるかも?という好奇心が沸いたので。
夏からやっている連続犯行予告にもそろそろ飽きてきていて次の展開に行くタイミングを計っていたこともあり、
iesysを発見されたらそれはそれでいいかなという気持ちでした。
結果的にはその後一度もオンラインにならず、観察を続けることはできなかったのですが。

いずれはどこかで発見されるよう仕向け、また告白文でネタバラシするつもりだったというのも本当です。
何より誤認逮捕が明らかにならなければ、本当の攻撃対象である警察・検察に何のダメージも与えられないのですから。

■安部総裁殺害予告もやったのか?
私ではありません。
模倣犯?ということもちょっとだけ頭をかすめましたが、
10月上旬という時期から、模倣犯とするには時系列的な矛盾があります。
「遠隔操作」が言われ始めたのが10月7日ぐらいですが、安部さん殺害予告はそれより前からあったようなので、私の事件に触発されたという線は無いでしょう。
報道によると発信元とされるオーナーは否認しているとのこと。
私がやったのと類似の何らかの仕掛けによるものなのか何なのか、私にも分かりません。

■黒子のバスケ脅迫は
知りません 関係ないです

■「犯人像」についてコメント
メディアに出てくる「専門家」の方々が、各自好き勝手に犯人像を語るのはとても面白かったです。
的外れなのもあり、当たってるのもあり、いい感じにバラけていると感じています。
そもそもこれまでの行動・言動は、プロファイリングの面で犯人像を絞り込ませないための工夫を入れています。
・C#を使うような若者かもしれないし、「はだしのゲン」に思い入れのある中年かもしれない。
・皇室や神社を攻撃するような反日左翼かもしれないし、部落開放同盟を攻撃するような右翼かもしれない。
・アニメフィギュアコレクターなのかもしれないし、まったく興味が無いのかもしれない。
・「また来世~」などと、伊集院光ラジオのファンかもしれないし、そういうフリをしているだけなのかもしれない。
・将棋が好きなのかもしれないし、そうでないのかもしれない。
・引きこもりなのかもしれないし、アウトドア派なのかもしれない。

挙げればキリが無いけれど、こういう気まぐれで無軌道な動きはわざとやっています。
引き出しが多いほうだと人から言われるほうですが、私の引き出しにあるものも、全くの守備範囲のものも、程よくミックスして出しているわけです。
このドキュメントでまた材料が増えたわけですが、この段階で今度は「専門家」の方たちがどうプロファイリングするのか、かなり興味深いですね。

■捜査特別報奨金制度の対象となったことへのコメント
>犯人に関する情報について
>~この犯人を知っている
>~事件について噂話を聞いた
>このメールを送信した者を知っている
身近な人だろうと誰にも喋っていません。
このような情報は全宇宙の誰からも得られません。

>これらの言葉遣いや言い回しを使う者を知っている
>同じような表現を用いて文章を書く人を知っている
一般社会ではきわめて常識人ですので、それらのようなキチガイ文書を書くことはありません。
よって、私に関する情報は全宇宙の誰からも得られません。

>このような特徴を持つウイルスを過去に作成した人や団体を知っている。
>このウイルスを作成した者を知っている。
お話になりませんね(笑)

■片桐裕様へ
たしか就任直後から「2ch潰す」とか「ネット規制する」とかいろいろ言ってますね。
そんなに言論統制が好きなら、あなた日本人やめて中国の小役人にでもなったほうがいいのではないですか?
あなたの大好きな検閲・規制・弾圧がいっぱいでまさに理想の国ですね。誤認逮捕しても怒られないでしょう。
というわけで、貴様は今後発言するときは語尾に「アル」を付けて喋ること。(命令)

■改めて世の中に言いたいことは
私のように警察・検察裁判所に対して悔しい思いをされた方は多数いると思います。
上訴、再審請求、国賠請求、あるいはデモや街宣、出版、主張サイト開設、そういった法を侵さない正攻法の戦い方もいいですが、勝ち目は無い場合が多いです。
法が間違っているのなら、法を侵してでもどんどん逆襲すべきです。
国家権力という途方も無い相手と戦うのに、コソコソ隠れるゲリラ戦術を選択するのは卑怯でも何でもないことです。
戦うべき人が戦えば国は良い方向に向かう、そう信じています。

■最後に
私からは以上です。もう何も発信しません。
●●●@●●のメールアドレスはもう解約しましたので、メールをもらっても受け取れません。
最後まで読んでくれてありがとうございました。
さようなら。

(固有名詞などは一部●●で伏せててあります)

2009-04-10

mixi アプリ

あまちゃんのをスルーしてたけど

Google App Engineの方がいろいろ面白いことが出来ると思うけど。

http://anond.hatelabo.jp/20090410165102

「え?mixiアプリってそういうこと?」と、びっくりした。

これ、GAE関係ないやん。OpenSocialやん。って、OpenSocialよくしらんけど。

あれって、何処まで出来るの?増田の記事を扱えたりする?

ま、JSONPとかYQLとか使ってがんばれば増田リーダーも不可能ではない気がするけど。

とりあえずmixi使ってない身としては、なーんにも思いつきません。

2009-01-20

d:id:naoyaさま

このたびは、御社はてラボ内のサービスの一つ「はてな匿名ダイアリー」において、正式サービスではないにもかかわらず、迅速な荒らし対策を行っていただき、誠に有難う御座いました。

心より御礼申し上げます。

さて、上記対策により、一部閲覧し難いエントリーも正常に表示されるようになりましたが、しかし、その対策による影響とは断定できるわけではありませんが、一部機能に不具合が生じております。

具体的には、エントリーパーマリンクのページに付加されます、トラックバックツリーにおきまして、本文の一部表示を全文表示に展開できる「その場で全文機能*1」が動作しなくなっております。

原因としましては、modeパラメータに対しjsonを指定した際の応答が、本来jsonまたはjsonp形式となるはずが、HTMLエスケープされた上で幾つかのHTMLタグが付加されているためです。

多忙の中、このようなお願いが甚だ失礼とも存じますが、すばらしい機能である「その場で全文機能*1」が正常に動作しない現状は非常に残念であり、また荒らし行為への対策を完璧にするためにも、ご対応をして頂けないものかと希望しております。

御社のますますのご発展をお祈りいたしております。

*1 誠に勝手ではありますが、呼称が定まっておりませんでしたので、僭越ながら命名させていただきました。

2007-10-15

革命とはキャズム超えをいう

http://anond.hatelabo.jp/20071015180844

優れた技術は簡単に生まれるものではない。長い下積みを経て熟成された技術が、あるきっかけでキャズムを超える。それはちょっとした発想の転換だったりテクニックだったり、そして多くはマーケティングタイミングだったりする。そのため、そこに至るまでの積み重ねから見れば、ギャズムを超えたその技術自体は大したものではない事が大い。しかし、革命とよばれる事により生ずる牽引力が技術の発展に与える影響は大きい。

例えばWWW。ティム・バーナーズ=リーがそれを公開したのは90年頃。このシステムHTMLによるリンク画像も扱えるブラウザ Mosaic の登場とともに爆発的な普及を遂げ、インターネット革命をもたらした。しかし、このHTMLの基礎となる概念ハイパーテキストは古くからある。そして60年代にはそれを使用したシステムNLSがあり、また、HTMLの記述方法の基礎SGML60年代のGMLを祖としている。これらの技術も、世界がつなげたTCP/IPやそれを支えたUNIX、さらにそれらのシステムを動かし、画像を扱えるまでに高性能化したコンピュータとそれを支えるLSIの製造技術の支えがあってのものである。そしてそれは、時間をかけて主要ブラウザの標準機能となったJavascriptストレスなく動かすPCや、非同期に数多く寄せられるリクエストも処理できるRDBMやサーバを生み、古くからある技術を利用したAJAXJSONPが新たな革命をもたらすといわれている。

2007-10-03

Re: anond:20070902125421

nobracketの指定方法はBKっぽい気配がする。

それはともかく'callback'を設定できるようにしてJSONP対応にするのもよくね?

2007-07-19

/* Ten */
if (typeof(Ten) == 'undefined') {
    Ten = {};
}
Ten.NAME = 'Ten';
Ten.VERSION = 0.06;

/* Ten.Class */
Ten.Class = function(klass, prototype) {
    if (klass && klass.initialize) {
	var c = klass.initialize;
    } else if(klass && klass.base) {
        var c = function() { return klass.base[0].apply(this, arguments) };
    } else {
	var c = function() {};
    }
    c.prototype = prototype || {};
    c.prototype.constructor = c;
    Ten.Class.inherit(c, klass);
    if (klass && klass.base) {
        for (var i = 0;  i < klass.base.length; i++) {
	    var parent = klass.base[i];
            if (i == 0) {
                c.SUPER = parent;
                c.prototype.SUPER = parent.prototype;
            }
            Ten.Class.inherit(c, parent);
            Ten.Class.inherit(c.prototype, parent.prototype);
        }
    }
    return c;
}
Ten.Class.inherit = function(child,parent) {
    for (var prop in parent) {
        if (typeof(child[prop]) != 'undefined' || prop == 'initialize') continue;
        child[prop] = parent[prop];
    }
}

/*
// Basic Ten Classes
**/

/* Ten.JSONP */
Ten.JSONP = new Ten.Class({
    initialize: function(uri,obj,method) {
        if (Ten.JSONP.Callbacks.length) {
            setTimeout(function() {new Ten.JSONP(uri,obj,method)}, 500);
            return;
        }
        var del = uri.match(/\?/) ? '&' : '?';
        uri += del + 'callback=Ten.JSONP.callback';
        if (!uri.match(/timestamp=/)) {
            uri += '&' + encodeURI(new Date());
        }
        if (obj && method) Ten.JSONP.addCallback(obj,method);
        this.script = document.createElement('script');
        this.script.src = uri;
        this.script.type = 'text/javascript';
        document.getElementsByTagName('head')[0].appendChild(this.script);
    },
    addCallback: function(obj,method) {
        Ten.JSONP.Callbacks.push({object: obj, method: method});
    },
    callback: function(args) {
        // alert('callback called');
        var cbs = Ten.JSONP.Callbacks;
        for (var i = 0; i < cbs.length; i++) {
            var cb = cbs[i];
            cb.object[cb.method].call(cb.object, args);
        }
        Ten.JSONP.Callbacks = [];
    },
    MaxBytes: 8000,
    Callbacks: []
});

/* Ten.XHR */
Ten.XHR = new Ten.Class({
    initialize: function(uri,opts,obj,method) {
        if (!uri) return;
        this.request = Ten.XHR.getXMLHttpRequest();
        this.callback = {object: obj, method: method};
        var xhr = this;
        var prc = this.processReqChange;
        this.request.onreadystatechange = function() {
            prc.apply(xhr, arguments);
        }
        var method = opts.method || 'GET';
        this.request.open(method, uri, true);
        if (method == 'POST') {
            this.request.setRequestHeader('Content-Type',
                                          'application/x-www-form-urlencoded');
        }
        var data = opts.data ? Ten.XHR.makePostData(opts.data) : null;
        this.request.send(data);
    },
    getXMLHttpRequest: function() {
        var xhr;
        var tryThese = [
            function () { return new XMLHttpRequest(); },
            function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
            function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
            function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
        ];
        for (var i = 0; i < tryThese.length; i++) {
            var func = tryThese[i];
            try {
                xhr = func;
                return func();
            } catch (e) {
                //alert(e);
            }
        }
        return xhr;
    },
    makePostData: function(data) {
        var pairs = [];
        var regexp = /%20/g;
        for (var k in data) {
            var v = data[k].toString();
            var pair = encodeURIComponent(k).replace(regexp,'+') + '=' +
                encodeURIComponent(v).replace(regexp,'+');
            pairs.push(pair);
        }
        return pairs.join('&');
    }
},{
    processReqChange: function() {
        var req = this.request;
        if (req.readyState == 4) {
            if (req.status == 200) {
                var cb = this.callback;
                cb.object[cb.method].call(cb.object, req);
            } else {
                alert("There was a problem retrieving the XML data:\n" +
                      req.statusText);
            }
        }
    }
});

/* Ten.Observer */
Ten.Observer = new Ten.Class({
    initialize: function(element,event,obj,method) {
        var func = obj;
        if (typeof(method) == 'string') {
            func = obj[method];
        }
        this.element = element;
        this.event = event;
        this.listener = function(event) {
            return func.call(obj, new Ten.Event(event || window.event));
        }
        if (this.element.addEventListener) {
            if (this.event.match(/^on(.+)$/)) {
                this.event = RegExp.$1;
            }
            this.element.addEventListener(this.event, this.listener, false);
        } else if (this.element.attachEvent) {
            this.element.attachEvent(this.event, this.listener);
        }
    }
},{
    stop: function() {
        if (this.element.removeEventListener) {
            this.element.removeEventListener(this.event,this.listener,false);
        } else if (this.element.detachEvent) {
            this.element.detachEvent(this.event,this.listener);
        }
    }
});

/* Ten.Event */
Ten.Event = new Ten.Class({
    initialize: function(event) {
        this.event = event;
    },
    keyMap: {
        8:"backspace", 9:"tab", 13:"enter", 19:"pause", 27:"escape", 32:"space",
        33:"pageup", 34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up",
        39:"right", 40:"down", 44:"printscreen", 45:"insert", 46:"delete",
        112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7",
        119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12",
        144:"numlock", 145:"scrolllock"
    }
},{
    mousePosition: function() {
        if (!this.event.clientX) return;
        return Ten.Geometry.getMousePosition(this.event);
    },
    isKey: function(name) {
        var ecode = this.event.keyCode;
        if (!ecode) return;
        var ename = Ten.Event.keyMap[ecode];
        if (!ename) return;
        return (ename == name);
    },
    targetIsFormElements: function() {
        var target = this.event.target;
        if (!target) return;
        var T = (target.tagName || '').toUpperCase();
        return (T == 'INPUT' || T == 'SELECT' || T == 'OPTION' ||
                T == 'BUTTON' || T == 'TEXTAREA');
    },
    stop: function() {
        var e = this.event;
        if (e.stopPropagation) {
            e.stopPropagation();
            e.preventDefault();
        } else {
            e.cancelBubble = true;
            e.returnValue = false;
        }
    }
});

/* Ten.DOM */
Ten.DOM = new Ten.Class({
    getElementsByTagAndClassName: function(tagName, className, parent) {
        if (typeof(parent) == 'undefined') {
            parent = document;
        }
        var children = parent.getElementsByTagName(tagName);
        if (className) { 
            var elements = [];
            for (var i = 0; i < children.length; i++) {
                var child = children[i];
                var cls = child.className;
                if (!cls) {
                    continue;
                }
                var classNames = cls.split(' ');
                for (var j = 0; j < classNames.length; j++) {
                    if (classNames[j] == className) {
                        elements.push(child);
                        break;
                    }
                }
            }
            return elements;
        } else {
            return children;
        }
    },
    removeEmptyTextNodes: function(element) {
        var nodes = element.childNodes;
        for (var i = 0; i < nodes.length; i++) {
            var node = nodes[i];
            if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
                node.parentNode.removeChild(node);
            }
        }
    },
    nextElement: function(elem) {
        do {
            elem = elem.nextSibling;
        } while (elem && elem.nodeType != 1);
        return elem;
    },
    prevElement: function(elem) {
        do {
            elem = elem.previousSibling;
        } while (elem && elem.nodeType != 1);
        return elem;
    },
    scrapeText: function(node) {
        var rval = [];
        (function (node) {
            var cn = node.childNodes;
            if (cn) {
                for (var i = 0; i < cn.length; i++) {
                    arguments.callee.call(this, cn[i]);
                }
            }
            var nodeValue = node.nodeValue;
            if (typeof(nodeValue) == 'string') {
                rval.push(nodeValue);
            }
        })(node);
        return rval.join('');
    },
    onLoadFunctions: [],
    loaded: false,
    timer: null,
    addEventListener: function(event,func) {
        if (event != 'load') return;
        Ten.DOM.onLoadFunctions.push(func);
        Ten.DOM.checkLoaded();
    },
    checkLoaded: function() {
        var c = Ten.DOM;
        if (c.loaded) return true;
        if (document && document.getElementsByTagName &&
            document.getElementById && document.body) {
            if (c.timer) {
                clearInterval(c.timer);
                c.timer = null;
            }
            for (var i = 0; i < c.onLoadFunctions.length; i++) {
                    c.onLoadFunctions[i]();
            }
            c.onLoadFunctions = [];
            c.loaded = true;
        } else {
            c.timer = setInterval(c.checkLoaded, 13);
        }
    }
});

/* Ten.Style */
Ten.Style = new Ten.Class({
    applyStyle: function(elem, style) {
        for (prop in style) {
            elem.style[prop] = style[prop];
        }
    }
});

/* Ten.Geometry */
Ten.Geometry = new Ten.Class({
    initialize: function() {
        if (Ten.Geometry._initialized) return;
        var func = Ten.Geometry._functions;
        var de = document.documentElement;
        if (window.innerWidth) {
            func.getWindowWidth = function() { return window.innerWidth; }
            func.getWindowHeight = function() { return window.innerHeight; }
            func.getXScroll = function() { return window.pageXOffset; }
            func.getYScroll = function() { return window.pageYOffset; }
        } else if (de && de.clientWidth) {
            func.getWindowWidth = function() { return de.clientWidth; }
            func.getWindowHeight = function() { return de.clientHeight; }
            func.getXScroll = function() { return de.scrollLeft; }
            func.getYScroll = function() { return de.scrollTop; }
        } else if (document.body.clientWidth) {
            func.getWindowWidth = function() { return document.body.clientWidth; }
            func.getWindowHeight = function() { return document.body.clientHeight; }
            func.getXScroll = function() { return document.body.scrollLeft; }
            func.getYScroll = function() { return document.body.scrollTop; }
        }
        Ten.Geometry._initialized = true;
    },
    _initialized: false,
    _functions: {},
    getScroll: function() {
        if (!Ten.Geometry._initialized) new Ten.Geometry;
        return {
            x: Ten.Geometry._functions.getXScroll(),
            y: Ten.Geometry._functions.getYScroll()
        };
    },
    getMousePosition: function(pos) {
        // pos should have clientX, clientY same as mouse event
        if ((navigator.userAgent.indexOf('Safari') > -1) &&
            (navigator.userAgent.indexOf('Version/') < 0)) {
            return {
                x: pos.clientX,
                y: pos.clientY
            };
        } else {
            var scroll = Ten.Geometry.getScroll();
            return {
                x: pos.clientX + scroll.x,
                y: pos.clientY + scroll.y
            };
        }
    },
    getElementPosition: function(e) {
        return {
            x: e.offsetLeft,
            y: e.offsetTop
        };
    },
    getWindowSize: function() {
        if (!Ten.Geometry._initialized) new Ten.Geometry;
        return {
            w: Ten.Geometry._functions.getWindowWidth(),
            h: Ten.Geometry._functions.getWindowHeight()
        };
    }
});

/* Ten.Position */
Ten.Position = new Ten.Class({
    initialize: function(x,y) {
        this.x = x;
        this.y = y;
    },
    subtract: function(a,b) {
        return new Ten.Position(a.x - b.x, a.y - b.y);
    }
});

/*
// require Ten.js
**/

/* Ten.SubWindow */
Ten.SubWindow = new Ten.Class({
    initialize: function() {
        var c = this.constructor;
        if (c.singleton && c._cache) {
            return c._cache;
        }
        var div = document.createElement('div');
        Ten.Style.applyStyle(div, Ten.SubWindow._baseStyle);
        Ten.Style.applyStyle(div, c.style);
        this.window = div;
        this.addContainerAndCloseButton();
        document.body.appendChild(div);
        if (c.draggable) {
            this._draggable = new Ten.Draggable(div, this.handle);
        }
        if (c.singleton) c._cache = this;
        return this;
    },
    _baseStyle: {
        color: '#000',
        position: 'absolute',
        display: 'none',
        zIndex: 2,
        left: 0,
        top: 0,
        backgroundColor: '#fff',
        border: '1px solid #bbb'
    },
    style: {
        padding: '2px',
        textAlign: 'center',
        borderRadius: '6px',
        MozBorderRadius: '6px',
        width: '100px',
        height: '100px'
    },
    handleStyle: {
        position: 'absolute',
        top: '0px',
        left: '0px',
        backgroundColor: '#f3f3f3',
        borderBottom: '1px solid #bbb',
        width: '100%',
        height: '30px'
    },
    containerStyle: {
        margin: '32px 0 0 0',
        padding: '0 10px'
    },
    // closeButton: 'close.gif',
    closeButton: 'http://s.hatena.com/images/close.gif',
    closeButtonStyle: {
        position: 'absolute',
        top: '8px',
        right: '10px',
        cursor: 'pointer'
    },
    _baseScreenStyle: {
        position: 'absolute',
        top: '0px',
        left: '0px',
        display: 'none',
        zIndex: 1,
        overflow: 'hidden',
        width: '100%',
        height: '100%'
    },
    screenStyle: {},
    showScreen: true,
    singleton: true,
    draggable: true,
    _cache: null
},{
    screen: null,
    windowObserver: null,
    visible: false,
    addContainerAndCloseButton: function() {
        var win = this.window;
        var c = this.constructor;
        var div = document.createElement('div');
        win.appendChild(div);
        Ten.Style.applyStyle(div, c.containerStyle);
        this.container = div;
        if (c.handleStyle) {
            var handle = document.createElement('div');
            Ten.Style.applyStyle(handle, c.handleStyle);
            win.appendChild(handle);
            this.handle = handle;
        }
        if (c.closeButton) {
	    var btn = document.createElement('img');
            btn.src = c.closeButton;
            btn.alt = 'close';
            Ten.Style.applyStyle(btn, c.closeButtonStyle);
            win.appendChild(btn);
            new Ten.Observer(btn, 'onclick', this, 'hide');
            this.closeButton = btn;
        }
        if (c.showScreen) {
            var screen = document.createElement('div');
            Ten.Style.applyStyle(screen, Ten.SubWindow._baseScreenStyle);
            Ten.Style.applyStyle(screen, c.screenStyle);
            document.body.appendChild(screen);
            this.screen = screen;
            new Ten.Observer(screen, 'onclick', this, 'hide');
        }
    },
    show: function(pos) {
        pos = (pos.x && pos.y) ? pos : {x:0, y:0};
        with (this.window.style) {
            display = 'block';
            left = pos.x + 'px';
            top = pos.y + 'px';
        }
        if (this.screen) {
            with (this.screen.style) {
                display = 'block';
                left = Ten.Geometry.getScroll().x + 'px';
                top = Ten.Geometry.getScroll().y + 'px';
            }
        }
        this.windowObserver = new Ten.Observer(document.body, 'onkeypress', this, 'handleEscape');
        this.visible = true;
    },
    handleEscape: function(e) {
        if (!e.isKey('escape')) return;
        this.hide();
    },
    hide: function() {
        if (this._draggable) this._draggable.endDrag();
        this.window.style.display = 'none';
        if (this.screen) this.screen.style.display = 'none';
        if (this.windowObserver) this.windowObserver.stop();
        this.visible = false;
    }
});

/* Ten.Draggable */
Ten.Draggable = new Ten.Class({
    initialize: function(element,handle) {
        this.element = element;
        this.handle = handle || element;
        this.startObserver = new Ten.Observer(this.handle, 'onmousedown', this, 'startDrag');
        this.handlers = [];
    }
},{
    startDrag: function(e) {
        if (e.targetIsFormElements()) return;
        this.delta = Ten.Position.subtract(
            e.mousePosition(),
            Ten.Geometry.getElementPosition(this.element)
        );
        this.handlers = [
            new Ten.Observer(document, 'onmousemove', this, 'drag'),
            new Ten.Observer(document, 'onmouseup', this, 'endDrag'),
            new Ten.Observer(this.element, 'onlosecapture', this, 'endDrag')
        ];
        e.stop();
    },
    drag: function(e) {
        var pos = Ten.Position.subtract(e.mousePosition(), this.delta);
        Ten.Style.applyStyle(this.element, {
            left: pos.x + 'px',
            top: pos.y + 'px'
        });
        e.stop();
    },
    endDrag: function(e) {
        for (var i = 0; i < this.handlers.length; i++) {
            this.handlers[i].stop();
        }
        if(e) e.stop();
    }
});

/* Hatena */
if (typeof(Hatena) == 'undefined') {
    Hatena = {};
}

/* Hatena.User */
Hatena.User = new Ten.Class({
    initialize: function(name) {
        this.name = name;
    },
    getProfileIcon: function(name) {
        if (!name) name = 'user';
        var pre = name.match(/^[\w-]{2}/)[0];
        var img = document.createElement('img');
        img.src = 'http://www.hatena.ne.jp/users/' + pre + '/' + name + '/profile_s.gif';
        img.alt = name;
        img.setAttribute('class', 'profile-icon');
        img.setAttribute('width','16px');
        img.setAttribute('height','16px');
        with (img.style) {
            margin = '0 3px';
            border = 'none';
            verticalAlign = 'middle';
        }
        return img;
    }
}, {
    profileIcon: function() {
        return Hatena.User.getProfileIcon(this.name);
    }
});

/* Hatena.Star */
if (typeof(Hatena.Star) == 'undefined') {
    Hatena.Star = {};
}

/*
// Hatena.Star.* classes //
**/
if (window.location && window.location.host.match(/hatena\.com/)) {
    Hatena.Star.BaseURL = 'http://s.hatena.com/';
} else {
    Hatena.Star.BaseURL = 'http://s.hatena.ne.jp/';
}
Hatena.Star.Token = null;

/* Hatena.Star.User */
Hatena.Star.User = new Ten.Class({
    base: [Hatena.User],
    initialize: function(name) {
        if (Hatena.Star.User._cache[name]) {
            return Hatena.Star.User._cache[name];
        } else {
            this.name = name;
            Hatena.Star.User._cache[name] = this;
            return this;
        }
    },
    _cache: {}
},{
    userPage: function() {
        return Hatena.Star.BaseURL + this.name + '/';
    }
});

/* Hatena.Star.Entry */
Hatena.Star.Entry = new Ten.Class({
    initialize: function(e) {
        this.entry = e;
        this.uri = e.uri;
        this.title = e.title;
        this.star_container = e.star_container;
        this.comment_container = e.comment_container;
        this.stars = [];
        this.comments = [];
    },
    maxStarCount: 11
},{
    flushStars: function() {
        this.stars = [];
        this.star_container.innerHTML = '';
    },
    bindStarEntry: function(se) {
        this.starEntry = se;
        for (var i = 0; i < se.stars.length; i++) {
            if (typeof(se.stars[i]) == 'number') {
                this.stars.push(new Hatena.Star.InnerCount(se.stars[i],this));
            } else {
                this.stars.push(new Hatena.Star.Star(se.stars[i]));
            }
        }
        if (se.comments && !this.comments.length) {
            for (var i = 0; i < se.comments.length; i++) {
                this.comments.push(new Hatena.Star.Comment(se.comments[i]));
            }
        }
        this.can_comment = se.can_comment;
    },
    setCanComment: function(v) {
        this.can_comment = v;
    },
    showButtons: function() {
        this.addAddButton();
        this.addCommentButton();
    },
    addAddButton: function() {
        if (this.star_container) {
            this.addButton = new Hatena.Star.AddButton(this);
            this.star_container.appendChild(this.addButton);
        }
    },
    addCommentButton: function() {
        if (this.comment_container) {
            this.commentButton = new Hatena.Star.CommentButton(this);
            this.comment_container.appendChild(this.commentButton.img);
        }
    },
    showStars: function() {
        var klass = this.constructor;
        // if (this.stars.length > klass.maxStarCount) {
        //     var ic = new Hatena.Star.InnerCount(this.stars.slice(1,this.stars.length));
        //     this.star_container.appendChild(this.stars[0]);
        //     this.star_container.appendChild(ic);
        //     this.star_container.appendChild(this.stars[this.stars.length - 1]);
        // } else {
        for (var i = 0; i < this.stars.length; i++) {
            this.star_container.appendChild(this.stars[i]);
        }
    },
    showCommentButton: function() {
        if (this.can_comment) {
            this.commentButton.show();
            if (this.comments.length) this.commentButton.activate();
        } else {
            // this.commentButton.hide();
        }
    },
    addStar: function(star) {
        this.stars.push(star);
        this.star_container.appendChild(star);
    },
    addComment: function(com) {
        if (!this.comments) this.comments = [];
        if (this.comments.length == 0) {
            this.commentButton.activate();
        }
        this.comments.push(com);
    },
    showCommentCount: function() {
        this.comment_container.innerHTML += this.comments.length;
    }
});

/* Hatena.Star.Button */
Hatena.Star.Button = new Ten.Class({
    createButton: function(args) {
        var img = document.createElement('img');
        img.src = args.src;
        img.alt = img.title = args.alt;
        with (img.style) {
	    cursor = 'pointer';
	    margin = '0 3px';
            padding = '0';
            border = 'none';
            verticalAlign = 'middle';
        }
        return img;
    }
});

/* Hatena.Star.AddButton */
Hatena.Star.AddButton = new Ten.Class({
    base: ['Hatena.Star.Button'],
    initialize: function(entry) {
        this.entry = entry;
        this.lastPosition = null;
        var img = Hatena.Star.Button.createButton({
            src: Hatena.Star.AddButton.ImgSrc,
            alt: 'Add Star'
        });
        this.observer = new Ten.Observer(img,'onclick',this,'addStar');
        this.img = img;
        return img;
    },
    ImgSrc: Hatena.Star.BaseURL + 'images/add.gif'
},{
    addStar: function(e) {
        this.lastPosition = e.mousePosition();
        var uri = Hatena.Star.BaseURL + 'star.add.json?uri=' + encodeURIComponent(this.entry.uri) +
            '&title=' + encodeURIComponent(this.entry.title);
        if (Hatena.Star.Token) {
            uri += '&token=' + Hatena.Star.Token;
        }
        new Ten.JSONP(uri, this, 'receiveResult');
    },
    receiveResult: function(args) {
        var name = args ? args.name : null;
        if (name) {
            this.entry.addStar(new Hatena.Star.Star({name: name}));
            //alert('Succeeded in Adding Star ' + args);
        } else if (args.errors) {
            var pos = this.lastPosition;
            pos.x -= 10;
            pos.y += 25;
            var scroll = Ten.Geometry.getScroll();
            var scr = new Hatena.Star.AlertScreen();
            var alert = args.errors[0];
            scr.showAlert(alert, pos);
        }
    }
});

/* Hatena.Star.CommentButton */
Hatena.Star.CommentButton = new Ten.Class({
    base: ['Hatena.Star.Button'],
    initialize: function(entry) {
        this.entry = entry;
        this.lastPosition = null;
        var img = Hatena.Star.Button.createButton({
            src: Hatena.Star.CommentButton.ImgSrc,
            alt: 'Comments'
        });
        img.style.display = 'none';
        this.observer = new Ten.Observer(img,'onclick',this,'showComments');
        this.img = img;
    },
    ImgSrc: Hatena.Star.BaseURL + 'images/comment.gif',
    ImgSrcActive: Hatena.Star.BaseURL + 'images/comment_active.gif'
},{
    showComments: function(e) {
        if (!this.screen) this.screen = new Hatena.Star.CommentScreen();
        this.screen.bindEntry(this.entry);
        var pos = e.mousePosition();
        pos.y += 25;
        this.screen.showComments(this.entry, pos);
    },
    hide: function() {
        this.img.style.display = 'none';
    },
    show: function() {
        this.img.style.display = 'inline';
    },
    activate: function() {
        this.show();
        this.img.src = Hatena.Star.CommentButton.ImgSrcActive;
    }
});

/* Hatena.Star.Star */
Hatena.Star.Star = new Ten.Class({
    initialize: function(args) {
        if (args.img) {
            this.img = args.img;
            this.name = this.img.getAttribute('alt');
        } else {
            this.name = args.name;
            var img = document.createElement('img');
            img.src = Hatena.Star.Star.ImgSrc;
            img.alt = this.name;
            with (img.style) {
                padding = '0';
                border = 'none';
            }
            this.img = img;
        }
	new Ten.Observer(this.img,'onmouseover',this,'showName');
	new Ten.Observer(this.img,'onmouseout',this,'hideName');
	if (this.name) {
            this.user = new Hatena.Star.User(this.name);
            this.img.style.cursor = 'pointer';
            new Ten.Observer(this.img,'onclick',this,'goToUserPage');
        }
        if (args.count && args.count > 1) {
            var c = document.createElement('span');
            c.setAttribute('class', 'hatena-star-inner-count');
            Ten.Style.applyStyle(c, Hatena.Star.InnerCount.style);
            c.innerHTML = args.count;
            var s = document.createElement('span');
            s.appendChild(img);
            s.appendChild(c);
            return s;
        } else {
            return this.img;
        }
    },
    ImgSrc: Hatena.Star.BaseURL + 'images/star.gif'
},{
    showName: function(e) {
        if (!this.screen) this.screen = new Hatena.Star.NameScreen();
        var pos = e.mousePosition();
        pos.x += 10;
        pos.y += 25;
        this.screen.showName(this.name, pos);
    },
    hideName: function() {
        if (!this.screen) return;
        this.screen.hide();
    },
    goToUserPage: function() {
        window.location = this.user.userPage();
    }
});

/* Hatena.Star.InnerCount */
Hatena.Star.InnerCount = new Ten.Class({
    initialize: function(count, e) {
        this.count = count;
        this.entry = e;
        var c = document.createElement('span');
        c.setAttribute('class', 'hatena-star-inner-count');
        Ten.Style.applyStyle(c, Hatena.Star.InnerCount.style);
        c.style.cursor = 'pointer';
        c.innerHTML = count;
        new Ten.Observer(c,'onclick',this,'showInnerStars');
        this.container = c;
        return c;
    },
    style: {
        color: '#f4b128',
        fontWeight: 'bold',
        fontSize: '80%',
        fontFamily: '"arial", sans-serif',
        margin: '0 2px'
    }
},{
    showInnerStars: function() {
        var url = Hatena.Star.BaseURL + 'entry.json?uri=' +
        encodeURIComponent(this.entry.uri);
        new Ten.JSONP(url, this, 'receiveStarEntry');
    },
    receiveStarEntry: function(res) {
        var se = res.entries[0];
        var e = this.entry;
        if (encodeURIComponent(se.uri) != encodeURIComponent(e.uri)) return;
        e.flushStars();
        e.bindStarEntry(se);
        e.addAddButton();
        e.showStars();
    }
});

/* Hatena.Star.Comment */
Hatena.Star.Comment = new Ten.Class({
    initialize: function(args) {
        this.name = args.name;
        this.body = args.body;
    }
},{
    asElement: function() {
        var div = document.createElement('div');
        with (div.style) {
            margin = '0px 0';
            padding = '5px 0';
            borderBottom = '1px solid #ddd';
        }
        var ico = Hatena.User.getProfileIcon(this.name);
        div.appendChild(ico);
        var span = document.createElement('span');
        with(span.style) {
            fontSize = '90%';
        }
        span.innerHTML = this.body;
        div.appendChild(span);
        return div;
    }
});

/* Hatena.Star.NameScreen */
Hatena.Star.NameScreen = new Ten.Class({
    base: [Ten.SubWindow],
    style: {
        padding: '2px',
        textAlign: 'center'
    },
    containerStyle: {
        margin: 0,
        padding: 0
    },
    handleStyle: null,
    showScreen: false,
    closeButton: null,
    draggable: false
},{
    showName: function(name, pos) {
        this.container.innerHTML = '';
        this.container.appendChild(Hatena.User.getProfileIcon(name));
        this.container.appendChild(document.createTextNode(name));
        this.show(pos);
    }
});

/* Hatena.Star.AlertScreen */
Hatena.Star.AlertScreen = new Ten.Class({
    base: [Ten.SubWindow],
    style: {
        padding: '2px',
        textAlign: 'center',
        borderRadius: '6px',
        MozBorderRadius: '6px',
        width: '240px',
        height: '120px'
    },
    handleStyle: {
        position: 'absolute',
        top: '0px',
        left: '0px',
        backgroundColor: '#f3f3f3',
        borderBottom: '1px solid #bbb',
        width: '100%',
        height: '30px',
        borderRadius: '6px 6px 0 0',
        MozBorderRadius: '6px 6px 0 0'
    }
},{
    showAlert: function(msg, pos) {
        this.container.innerHTML = msg;
        var win = Ten.Geometry.getWindowSize();
        var scr = Ten.Geometry.getScroll();
        var w = parseInt(this.constructor.style.width) + 20;
        if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
        this.show(pos);
    }
});

/* Hatena.Star.CommentScreen */
Hatena.Star.CommentScreen = new Ten.Class({
    base: [Ten.SubWindow],
    initialize: function() {
        var self = this.constructor.SUPER.call(this);
        if (!self.commentsContainer) self.addCommentsContainer();
        return self;
    },
    style: {
        width: '280px',
        height: '280px',
        overflowY: 'auto',
        padding: '2px',
        textAlign: 'center',
        borderRadius: '6px',
        MozBorderRadius: '6px'
    },
    handleStyle: {
        position: 'absolute',
        top: '0px',
        left: '0px',
        backgroundColor: '#f3f3f3',
        borderBottom: '1px solid #bbb',
        width: '100%',
        height: '30px',
        borderRadius: '6px 6px 0 0',
        MozBorderRadius: '6px 6px 0 0'
    },
    containerStyle: {
        margin: '32px 0 0 0',
        textAlign: 'left',
        padding: '0 10px'
    },
    getLoadImage: function() {
        var img = document.createElement('img');
        img.src = Hatena.Star.BaseURL + 'images/load.gif';
        img.setAttribute('alt', 'Loading');
        with (img.style) {
            verticalAlign = 'middle';
            margin = '0 2px';
        }
        return img;
    }
},{
    addCommentsContainer: function() {
        var div = document.createElement('div');
        with (div.style) {
            marginTop = '-3px';
        }
        this.container.appendChild(div);
        this.commentsContainer = div;
    },
    showComments: function(e, pos) {
        var comments = e.comments;
        if (!comments) comments = [];
        this.commentsContainer.innerHTML = '';
        for (var i=0; i<comments.length; i++) {
            this.commentsContainer.appendChild(comments[i].asElement());
        }
        if (e.starEntry && !e.can_comment) {
            this.hideCommentForm();
        } else {
            this.addCommentForm();
        }
        var win = Ten.Geometry.getWindowSize();
        var scr = Ten.Geometry.getScroll();
        var w = parseInt(this.constructor.style.width) + 20;
        if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
        this.show(pos);
    },
    bindEntry: function(e) {
        this.entry = e;
    },
    sendComment: function(e) {
        if (!e.isKey('enter')) return;
        var body = this.commentInput.value;
        if (!body) return;
        this.commentInput.disabled = 'true';
        this.showLoadImage();
        var url = Hatena.Star.BaseURL + 'comment.add.json?body=' + encodeURIComponent(body) +
            '&uri=' + encodeURIComponent(this.entry.uri) +
            '&title=' + encodeURIComponent(this.entry.title);
        new Ten.JSONP(url, this, 'receiveResult');
    },
    receiveResult: function(args) {
        if (!args.name || !args.body) return;
        this.commentInput.value = ''; 
        this.commentInput.disabled = '';
        this.hideLoadImage();
        var com = new Hatena.Star.Comment(args);
        this.entry.addComment(com);
        this.commentsContainer.appendChild(com.asElement());
    },
    showLoadImage: function() {
        if (!this.loadImage) return; 
        this.loadImage.style.display = 'inline';
    },
    hideLoadImage: function() {
        if (!this.loadImage) return; 
        this.loadImage.style.display = 'none';
    },
    hideCommentForm: function() {
        if (!this.commentForm) return;
        this.commentForm.style.display = 'none';
    },
    addCommentForm: function() {
        if (this.commentForm) {
            this.commentForm.style.display = 'block';
            return;
        }
        var form = document.createElement('div');
        this.container.appendChild(form);
        this.commentForm = form;
        with (form.style) {
            margin = '0px 0';
            padding = '5px 0';
            // borderTop = '1px solid #ddd';
        }
        //if (Hatena.Visitor) {
        //    form.appendChild(Hatena.Visitor.profileIcon());
        //} else {
        //    form.appendChild(Hatena.User.getProfileIcon());
        //}
        var input = document.createElement('input');
        input.type = 'text';
        with (input.style) {
            width = '215px';
	    border = '1px solid #bbb';
            padding = '3px';
        }
        form.appendChild(input);
        this.commentInput = input;
        var img = this.constructor.getLoadImage();
        this.loadImage = img;
        this.hideLoadImage();
        form.appendChild(img);
        new Ten.Observer(input,'onkeypress',this,'sendComment');
    }
});

/* Hatena.Star.EntryLoader */
Hatena.Star.EntryLoader = new Ten.Class({
    initialize: function() {
        var entries = Hatena.Star.EntryLoader.loadEntries();
        this.entries = [];
        for (var i = 0; i < entries.length; i++) {
            var e = new Hatena.Star.Entry(entries[i]);
            e.showButtons();
            this.entries.push(e);
        }
        this.getStarEntries();
    },
    createStarContainer: function() {
        var sc = document.createElement('span');
        sc.setAttribute('class', 'hatena-star-star-container');
        sc.style.marginLeft = '1px';
        return sc;
    },
    createCommentContainer: function() {
        var cc = document.createElement('span');
        cc.setAttribute('class', 'hatena-star-comment-container');
        cc.style.marginLeft = '1px';
        return cc;
    },
    scrapeTitle: function(node) {
        var rval = [];
        (function (node) {
            if (node.tagName == 'SPAN' &&
                (node.className == 'sanchor' ||
                 node.className == 'timestamp')) {
                     return;
            } else if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
                return;
            }
            var cn = node.childNodes;
            if (cn) {
                for (var i = 0; i < cn.length; i++) {
                    arguments.callee.call(this, cn[i]);
                }
            }
            var nodeValue = node.nodeValue;
            if (typeof(nodeValue) == 'string') {
                rval.push(nodeValue);
            }
        })(node);
        return rval.join('');
    },
    headerTagAndClassName: ['h3',null],
    getHeaders: function() {
        var t = Hatena.Star.EntryLoader.headerTagAndClassName;
        return Ten.DOM.getElementsByTagAndClassName(t[0],t[1],document);
    },
    loadEntries: function() {
        var entries = [];
        //var headers = document.getElementsByTagName('h3');
        var c = Hatena.Star.EntryLoader;
        var headers = c.getHeaders();
        for (var i = 0; i < headers.length; i++) {
            var header = headers[i];
            var a = header.getElementsByTagName('a')[0];
            if (!a) continue;
            var uri = a.href;
            var title = '';
            // Ten.DOM.removeEmptyTextNodes(header);
            var cns = header.childNodes;
            title = c.scrapeTitle(header);
            var cc = c.createCommentContainer();
            header.appendChild(cc);
            var sc = c.createStarContainer();
            header.appendChild(sc);
            entries.push({
                uri: uri,
                title: title,
                star_container: sc,
                comment_container: cc
            });
        }
        return entries;
    }
},{
    getStarEntries: function() {
        var url = Hatena.Star.BaseURL + 'entries.json?';
        for (var i = 0; i < this.entries.length; i++) {
            if (url.length > Ten.JSONP.MaxBytes) {
                new Ten.JSONP(url, this, 'receiveStarEntries');
                url = Hatena.Star.BaseURL + 'entries.json?';
            }
            url += 'uri=' + encodeURIComponent(this.entries[i].uri) + '&';
        }
        new Ten.JSONP(url, this, 'receiveStarEntries');
    },
    receiveStarEntries: function(res) {
        var entries = res.entries;
        if (!entries) entries = [];
        for (var i = 0; i < this.entries.length; i++) {
            var e = this.entries[i];
            for (var j = 0; j < entries.length; j++) {
                var se = entries[j];
                if (!se.uri) continue;
                if (encodeURIComponent(se.uri) == encodeURIComponent(e.uri)) {
                    e.bindStarEntry(se);
                    entries.splice(j,1);
                    break;
                }
            }
            if (typeof(e.can_comment) == 'undefined') {
                e.setCanComment(res.can_comment);
            }
            e.showStars();
            e.showCommentButton();
        }
    }
});

/* Hatena.Star.WindowObserver */
Hatena.Star.WindowObserver = new Ten.Class({
    initialize: funct


  

2007-07-13

はてなスター」で他人に罵詈雑言を浴びせる方法

基本的に他人を褒めることしかできない「はてなスター」で他人に罵詈雑言を浴びせる方法です。

 

ttp://s.hatena.ne.jp/star.add.json?uri=http%3A%2F%2Fd.hatena.ne.jp%2F【憎いあん畜生ID】%2F0000&title=【届けたい罵詈雑言UTF-8パーセントエンコード)】&callback=Ten.JSONP.callback

 

これで

ttp://s.hatena.ne.jp/【憎いあん畜生ID】/blogs

メッセージが登録されるよ!

 

ttp://d.hatena.ne.jp/【憎いあん畜生ID】/0000

なんてページは作れないから、誰が★を送ってきたのかすらわからないよ!

仕様が変わったり、僕の勘違いだったら大変だから、ご利用は計画的に

 

1URIにつき1つしか登録されないから、複数のメッセージを送りたい場合は「0000」の部分を1回1回適当に変えようね!

 

まー、問題は、自分の

ttp://s.hatena.ne.jp/【ID】/blogs

なんて、ほとんどの人が見ないだろうってことだな。

 
ログイン ユーザー登録
ようこそ ゲスト さん