Page 2/16: 1 2 3 4 5 6 7 8 9 »

2007-07-04

書評「確率モデルによるWebデータ解析法 - データマイニング技法からe-コマースまで」

さっぱり理解できませんでした。

2007-06-23

つまらなくて役に立つ物を作るということ

プログラミングできるひとは「ゲーム作れよ」と言われることが多いような気がする。

ぶっちゃけゲームとか作れないし、たぶんウェブプログラマの多くはそうだ。
PerlやRubyやJavaScriptとかで何万ポリゴン動かしたりできない。
XMLをパースしたり、正規表現で置換したり、そういうのなら得意だ。
ゲームの人らは秒間3億ポリゴンとかやってるのに、何でこんなちまちましたことやってるんだろうと思ったりもする。

なんでこんな事やってるのかというと、面白いからやってるのだけれど、
プログラム書かない人らから見ると何やってるのか全然面白さが分からない、
3Dポリゴンが動いたり(乳が揺れたり)する方が面白いに決まってると思ってる。

彼らは失礼極まりなくて、リーナストーバルズに対しても
「お前の作ってるものは良く分からないから、ゲーム作れよ」って言うだろうね。
そういう連中を皆殺しにしないことには俺の人生始まらない。

世の中いろいろと不便なことが多くて、プログラマはそれを改善しようとしている。
世の中こんなにバグだらけなのに、バグほったらかしでゲーム作ってる場合じゃねえだろ、と思う。
電車の中で暇なのは不便なのでゲーム作ってくれてありがとうと思ったりもする。
でも基本的にはゲーム作ってる場合じゃねえだろ、って思う。

ものすげー面白いことをやろうとしている人に対して(それが一部の人にしか面白さが分からないからといって)
「お前の作ってるのは何の役に立つのかわかんねえよ。もっと俺を楽しませろよ。ゲーム作れよ、ゲーム!」
って言うのは失礼極まりないことだ。

面白くなければ意味がないとかいう人がいるけど、それって結局「大衆ウケしないと意味ない」ってのとほぼ同義だろ。
彼らは通常分厚いハッカーの壁で保護されているので、そういう言葉は届かないから、まあ良しとしても、
無知で無学で無教養のお前らにとって面白さが分からないからといって、価値がないということではないんだよ。

俺はつまんなくて役に立つ物を作るよ。そうありたい。
なんてことをカレー食いながら話した。
もちろん本意ではない。

2007-06-16

2007-06-12

Safari for Windows betaで日本語表示する方法


Preferences → Appearance で日本語のフォントを指定。
Documents and Settings\username\Application Data\Apple Computer\Safari\WebKitPreferences.plist
が、こんな風になる。


    <key>WebKitFixedFont</key>
    <string>MS ゴシック</string>
    <key>WebKitStandardFont</key>
    <string>MS Pゴシック</string>


で、フォント名から、実際のフォントファイルを参照する部分がおかしいみたいなので、
Documents and Settings\username\Local Settings\Application Data\Apple Computer\Safari\Fonts.plist
を弄る。



    <key>MS ゴシック</key>
    <string>C:\WINDOWS\Fonts\msgothic.ttc</string>
    <key>MS Pゴシック</key>
    <string>C:\WINDOWS\Fonts\msgothic.ttc</string>


ファイル編集するときはUTF-8で。


訂正。

上手くいったつもりで、フォントがOsakaのまんまになってた。上記の方法では上手くいかない。日本語を表示可能で、フォント名に日本語を含んでいないフォントを指定すれば日本語を表示できるようになる。

というわけで、MSゴシックで表示するにはフォント名の方を書き換えたら上手くいった。フォント名に日本語含まない日本語フォントを持ってれば、それを指定しても多分OK。ただしWebKitPreferences.plistを直接書き換えないと全部置き換わらないかも。

MSゴシックのフォント名をMS Gothic2に変更したフォントを作って、WebKitPreferences.plistを直接書き換えて指定すれば上手くいった。フォント名書き換えるのはttfnameというツールを使った。

http://www003.upp.so-net.ne.jp/kish/ttfname3.html


スクリーンショット
http://la.ma.la/misc/img/safari_for_win.png

フォント名をリネームするのに使ったxmlファイル。
http://la.ma.la/misc/msgothic.xml

----

手間をかけずに日本語表示を試したい人は

Documents and Settings\username\Application Data\Apple Computer\Safari\WebKitPreferences.plist
を編集してフォント名を指定している箇所を全て「MS UI Gothic」に変更すると良さげ。

2007-06-08

フィード吐いてそうなリンクを強調するブックマークレット

先日書いた、リンク先まとめて購読する機能のAPIが公開されたので、
http://blog.livedoor.jp/staff_reader/archives/51035779.html


こんなことができます。IE6の文字列制限ギリギリに圧縮(たぶん)
フィードを吐いてそうなリンクを強調

ソース
(function(){
 var api="http://rpc.reader.livedoor.com/feed/discover?url=";
 window.__feed_discover=function(r){
  var seen={};
  var links=document.links;len=links.length;
  for(var i=0;i<len;i++){
   var a=links[i];href=a.href;
   for(var l=0;l<r.length;l++){
    var f=r[l];
    if(f.link&&href.indexOf(f.link)!=-1&&!seen[f.link]){
     seen[f.link]=true;
     a.style.border="2px solid #F00";
     a.title=f.subscribers_count + " users / "+ f.feedlink;
    }
   }
  }
 };
 api+=encodeURIComponent(location.href)+'&format=json&callback=__feed_discover';
 var s=document.createElement('script');s.src=api;document.body.appendChild(s);
})();


あと、リダイレクタみたいなURL中にURLを含んでるようなケースに対応した。

さとみかんとか。さとみかんとか。さとみかんとか。
http://reader.livedoor.com/subscribe/?url=http%3A%2F%2Falimika.alib.jp%2Fsatomican%2F&extract=on

これで移行もばっちりです。
もうフィード吐いてないサイトなんか見向きもされなくなるといいですね。

2007-06-06

ハッシュキーの存在チェックを超高速に省メモリで行う方法

リンク先まとめて登録できる機能が付きました。
http://blog.livedoor.jp/staff_reader/archives/51034585.html

かとゆー家断絶からリンク張られてるサイトをまとめて登録とか
http://reader.livedoor.com/subscribe/?url=http%3A%2F%2Fwww6.ocn.ne.jp%2F~katoyuu%2F&extract=on

スタートマック体験モニタのブログをまとめて登録とか
http://reader.livedoor.com/subscribe/?url=http%3A%2F%2Fwww.apple.com%2Fjp%2Farticles%2Fstartmac_monitor_2%2Fwinners.html&extract=on

できます。

リンク先の全件にAuto Discoveryをかけると、件数次第でとんでもなく時間掛かってしまいますが、Auto Discoveryは使わずに、ページ内のリンクを抽出してデータベースから購読者数の多いフィードを出してます。で、データベースに問い合わせるのも件数次第では負荷が高いので、実際はオンメモリでフィードを提供していそうなサイトに絞り込んでから実行してます。URLの上の階層を辿っていってフィードを吐いてそうなURLを見つけたら返すという仕組み。

ここらへんはYAPC::Asiaで話したのと大体おんなじ。
http://la.ma.la/blog/diary_200704051627.htm

で、高速化のために内部でBloom::Filterというのを使ってます。

Bloom filterを使うといいよ。

2007-05-31

JavaScriptで出現回数のカウントをする際のコード

今までこう書いてたのが
count[key] = count[key] ? count[key] + 1 : 1;


こう書けることが判明した。
count[key] = ++count[key] || 1;


コメント欄への回答
count[key]がNumberまたはundefinedであるとして、個人的には
count[key] = (count[key] || 0) + 1;
のほうが好みです。
JavaScriptでは問題ないとはいえ、言語によってはi = ++iの動作が未定義だったりするので。

前者の書き方とこの書き方は実は問題があって、Object.prototypeに定義されてるメソッドとハッシュのキー名がかぶるとおかしくなる。なので本当はcount.hasOwnProperty(key)でチェックするのが正しいのだけれど、出現回数のカウントごときでメソッド呼び出しとかしたくない。

その点、後者の書き方だと++count["toString"]が上手いことNaNになってくれるので、気にしなくて良い。ハッシュのキーにprefixつけてる前提ならどちらにしろ気にしないでいいけど。

2007-05-30

HTMLドキュメントを解析して特徴的なループを見つけるBookmarklet

- 全てのDOMノードを列挙する
- ノードは次のように文字列化される。

0: /html[0]/body[0]/div
1: /html[0]/body[0]/div[0]/div
2: /html[0]/body[0]/div[0]/div[0]/ul[0]/li
3: /html[0]/body[0]/div[0]/div[0]/ul[0]/li
4: /html[0]/body[0]/div[0]/div[0]/ul[0]/li
5: /html[0]/body[0]/div[0]/div[0]/ul[0]/li


直前の階層までは添え字つき、最後のノードはタグ名のみにする。
class名、id名は排除する。各々のサイトのルールで記述されたruleよりも
タグのネスト構造の方が変化に強いし機械的に抽出しやすいのではないか?

出現回数でソートする。li要素2-5はループであることが分かる。
しかし、例えばリストの中に複数のリンクが含まれていた場合は、

/html[0]/body[0]/div[0]/div[0]/ul[0]/li[3]/a[0]
/html[0]/body[0]/div[0]/div[0]/ul[0]/li[3]/a[1]
/html[0]/body[0]/div[0]/div[0]/ul[0]/li[3]/a[2]
/html[0]/body[0]/div[0]/div[0]/ul[0]/li[3]/a[3]


というようなループも見つけることができるだろう。
この場合は「より短いパスでのループ」の方がスコアが高くなるようにする。

ループと思われるノード
この場合は/html[0]/body[0]/div[0]/div[0]/ul[0]/liの中身を解析する
例えばこんな感じに。
[
    {level:6, length:(下位のtextNodeのlengthの合計), text: textNodeを連結したもの }
    {level:6, length:(下位のtextNodeのlengthの合計), text: textNodeを連結したもの }
    {level:6, length:(下位のtextNodeのlengthの合計), text: textNodeを連結したもの }
]


- そのノードの配下に含まれる文章の長さが大きいほどスコアが加算される。
- link rel="next"から次のページを取得、同様に解析を行ってtextの内容で重複をチェックする
-- 例えば10件中9件が同じであればスコアを0.1倍に減らす。
-- 変化がないループはタグクラウドのような共通のパーツであると考えられる。
-- 次のページを見たときに内容が変化している箇所がメインコンテンツ部分。
-- ループから見て一つ親のノードがページの主要なコンテンツであると考えられる。
- offsetHeight,offsetWidthを使って描画サイズを調べる?ただしブラウザじゃないと無理。

というようなことを昨晩思いついたのでとりあえず、JavaScriptで書いてみた。
コードはこんな感じ、今のところ重み付けはなくて出現回数のカウントだけ。

http://la.ma.la/misc/js/guess_loop.js

ブックマークレットにして試せるようにしてみたのがこちら。

guess loop

書き忘れ、forEachとか使ってるのでFirefoxオンリーです。

2007-05-09

都合の悪いことを書いたら記事を消さずに修正しろ

削除したブログの元記事がlivedoor readerで消えていないのはなぜですか
http://knowledge.livedoor.com/24355


フィードを取得した際に特定の記事が削除されているかどうかを判別することは難しいです。

ブログの最新記事の内、1件が消されてる、みたいなケースに限れば、多分半日もかからないとは思うけど、古い記事の場合は把握のしようがない。あと、If-Modified-Sinceを解釈して前回取得以降の記事だけを送ってくるようなのもあり得るので、そういうのを間違えて消さないように厳格にやろうとすると、難しいことが多い。

なのでfeed aggregatorを始め各方面にキャッシュされた記事を消したいと思った場合は、単純に記事を消すのではなく「この記事は削除しました」とかで記事の内容を上書きしたほうが良い。

炎上中のブログをリロードしまくってるときにNot Foundならブラウザのキャッシュから復元できることもありますが、
別の内容に置き換わってたりすると「アッー!」ってなったり、よくありますよね。そんな感じ。

やる気がないとかそういうわけじゃないです。

フィードの配信側のコントロールがどこまで及ぶべきかという話は抜きにして(個人的にはそんなにcontrollableでなくて良いと思ってる)、現状「削除しましたよ」ということを相手に通知するのは、消すよりも上書きした方が効果が高いので、そうした方が良いですよ、という話。

2007-05-05

Gearman::UtilとGearman::WorkerをRubyに移植

追記:
元のソースを愚直に書き写しただけなのでRubyっぽくないです。
ちゃんとしたのがciされたようなので用済みです!

http://code.sixapart.com/svn/gearman/trunk/api/ruby/lib/
http://dan-erat.livejournal.com/83941.html

----
http://la.ma.la/misc/ruby/gearman/util.rb
http://la.ma.la/misc/ruby/gearman/worker.rb

RubyでGearmanのWorkerを書いて。
require 'gearman/worker'

worker = Gearman::Worker.new
worker.debug = 1
worker.job_servers("127.0.0.1")
worker.register_function("sum"){|job|
    (a, b) = job.arg.split(",")
    a + b
}
worker.work


Perlの側でこんな風に呼び出せる。
use strict;
use Gearman::Client;

my $gc = Gearman::Client->new;
$gc->job_servers("127.0.0.1");
my $ts = $gc->new_task_set;

for my $i(1..20){
    $ts->add_task("sum" => "3,4", {
        on_complete => sub{
            print "$i:". ${$_[0]}. "\n"
        }
    });
}
$ts->wait;


3+4が34って言われます。
とりあえず動いてるんだけど、なんかタスク追加したあとにselect待ちの状態になってくれないでビジーループになっちゃう。

あとで直す。もしくは誰か直して。

2007-04-22

livedoor Readerから開くウィンドウのtargetを固定

http://la.ma.la/misc/userjs/ldr_fix_target.user.js

(function(){
    var w = (typeof unsafeWindow == 'undefined') ? window : unsafeWindow;
    var b = "hoge";
    document.getElementsByTagName("base")[0].target = b;
    w.base_target = b;
    w._open = w.open;
    w["open"] = function(url){return w._open(url,b)};
})();

GreasemonkeyとSeaHorseで動作確認。

マウスのクリックで開くウィンドウだけなら
javascript:window.base_target="hoge";void(0);

これでいい。

メールでそういう要望が来てたので作ってみただけで、特に便利だということはありません。あと俺はサポートセンターじゃない。

2007-04-17

livedoor ReaderからYahoo!ブックマークを使う設定

設定変更→クリップの設定、を開いて



これを貼り付け。
http://bookmarks.yahoo.co.jp/bookmarklet/showpopup?t=[[title]]&u=[[url]]&ei=UTF-8


b押すとYahooブックマークの登録画面が出るようになる。

好きなのを使えばいいと思います。

2007-04-15

livedoor Readerで今読んでいるフィードをTwitterに送るGreasemonkeyスクリプト

10分の1ぐらいの確率で送ります。非公開設定の場合は送りません。

http://la.ma.la/misc/userjs/ldr_auto_twitter.user.js

これ参考にしました。
http://subtech.g.hatena.ne.jp/antipop/20070330/1175232802

----
変更履歴
- 連続で送ると鬱陶しそうなので、1回送ったら10分は送らないように。確率を1/5に変更。

2007-04-15
- 同じフィードを2秒以上見てた場合のみ送るように。
- encodeURIしてなかったのを修正。

2007-04-13

全力で勝手に添削に添削に添削の自転車置き場にマジレス

http://blog.livedoor.jp/dankogai/archives/50808279.html
http://d.hatena.ne.jp/amachang/20070413/1176421425

「Object.prototype」って書いちゃうと勘違いする人も多いと思うので、MyObject.prototypeとかSomeClass.prototypeとか何でも良いけど別の書き方にすべきだと思った。

Object.prototype = {/* ... */}は、よほど特殊な事情がない限り避けるべきで、
MyObject.prototype = {/* ... */}で困るのはconstructorプロパティが消えてしまうぐらいで、普通は困らない。

2007-04-11

bluewindからtwitterを更新できるようにRubyでシンプルなクライアントを書いた

bluewindのコマンドに登録しておいて詳細→パラメータでidとpassword入れた状態にしてbluewindで[twitter ほげほげ]とか入れると更新されるようにしてみた。exerbでexe化しようとしたらrb_io_set_nonblockが見つからないとかエラーが出たけどexerbのバージョンを4.10にしたら上手くいった。

で、Windowsで使うならJavaScriptの方が楽だった。
http://muumoo.jp/news/2007/04/10/0twitterclient.html

require 'net/http'
require 'kconv'
user = ARGV.shift
pass = ARGV.shift
status = ARGV.join(" ") || ""
status_utf8 = status.kconv(Kconv::UTF8, Kconv::SJIS);

# hack for jp
status_utf8 += " ."

Net::HTTP.version_1_2
req = Net::HTTP::Post.new('/statuses/update.json')
req.basic_auth user,pass
req.body = 'status=' + URI.encode(status_utf8)

Net::HTTP.start('twitter.com',80) {|http|
  res = http.request(req)
  print res.body
}


芸がないのでなでしこで書いた。10行です。
認証は 「username:password」を BASE64エンコード
「いまなにしてる?」と 尋ねる
もしそれが空ならば終わる
コメントはそれ
コメントに 「 .」を 追加
コメントはコメントをUTF8変換
コメントはコメントをURLエンコード
クエリは「status=」。クエリにコメントを追加
ヘッダは「Authorization: Basic 」。ヘッダに認証を追加
ヘッダと クエリを 「http://twitter.com/statuses/update.json」へ HTTPポスト