トップ(最新) | <前

nDiki : 実装

実装 - implementation

スポンサード リンク

Related term

2007年11月9日 (金)

Twitter ステータスを nDiki サイドバーに表示 このエントリーを含むはてなブックマーク

スポンサード リンク

公式の Flash 版 Twitter badge をこのページのサイドバーに表示していたが、以下の点でちょっと不満だった。

  • 「Flash, Just Me」: 自分のみのステータスを表示できるが、1度に1つのみ。キャッシュの関係で古い情報が表示されがち。
  • 「Flash, With Friends」: 自分のみのステータスを表示できない。
  • 「HTML/JavaScript」: JavaScript ファイル読み込みなので、Twitter 側が重いとページのその先のレンダリングが止まってしまう。

「自分の過去のステータスを一覧的にサイドバーに表示する」のがしたいことなのだが、ちょっとマッチしない。 ということで Twitter から RSS フィードを取ってきて、サイドバーに表示することにした。

使ったモジュールは URI::Fetch + XML::RSS + Date::Parse。 それとユーティリティとして WiKicker::HTML と WiKicker::URI。

  1. cron で定期的に Twitter から RSS フィードをとってきて、Perl スクリプトで HTML フラグメントに変換。
  2. DiKicker が読み込む(サイドバーを含む)フッタファイルに挿入。

と簡単に実装してみた。機能的には概ね満足。

今後は L:~ や URL自動リンク化、キーワードの自動リンク化を適宜したい。

◇ Twitter やってます。この記事が気にいったらぜひ twitter.com/Naney の follower になってください。


[ 11月9日全て ]

2007年12月29日 (土)

Twitter ベイジアンフィルタプロキシ このエントリーを含むはてなブックマーク

Twitter で following が増えてくるにつれて、タイムラインに目を通すのが大変になってきた(という程きちんと見ている訳ではないが)。 さっとタイムラインをなめて面白そうな情報をピックアップしたい時は、「おはよう」とか「風呂入った」とか「トイレ」とかは除外して読みたい(そういう書き込み自体は嫌いじゃないのだが、人生はあまりにも短い)。

Twit や P3:PeraPeraPrv では NG ワード指定ができて、それらを含むステータスは表示しないようにできるのだが、Twitter の書き込みは揺らぎが激しすぎて指定しきれないという弱点がる。

ということでベイジアンフィルタでフィルタリングしてみることにした。

自前で Twitter クライアントを作る気はないので、proxy の形でさっと実装してみた。

 #!/usr/bin/perl

 use strict;
 use warnings;

 use HTTP::Proxy;
 use HTTP::Proxy::BodyFilter::complete;

 my $proxy = HTTP::Proxy->new(port => 8088);
 $proxy->push_filter(response => HTTP::Proxy::BodyFilter::complete->new,
                     mime     => 'application/xml');
 $proxy->push_filter(response => Bsfilter->new,
                     mime     => 'application/xml');
 $proxy->start;

 {

   package Bsfilter;

   use File::Temp qw/tempfile/;
   use XML::XPath;
   use base qw(HTTP::Proxy::BodyFilter);

   sub filter {
     my ($self, $dataref, $message, $protocol, $buffer) = @_;
     return unless defined($$dataref) && $$dataref ne '';
     eval {
       my $xml = XML::XPath->new(xml => $$dataref);
       my @nodes = $xml->findnodes('/statuses/status/text/text()');
       return unless @nodes;
       for my $node (@nodes) {
         my $text = $node->getNodeValue;
         if (is_NG($text)) {
           $node->setNodeValue("[NG] $text");
         }
       }
       $$dataref = qq(<?xml version="1.0" encoding="UTF-8"?>\n);
       $$dataref .= $xml->get_context->toString;
       utf8::encode($$dataref);
     };
     if ($@) {
       warn $@;
     }
   }

   sub will_modify { 1 }

   sub is_NG {
     my ($text) = @_;

     my ($fh, $filename) = tempfile();
     utf8::encode($text);
     print $fh $text;
     close($fh);
     my $result
       = system(
       "bsfilter --homedir ~/.twitter-bsfilter --ignore-header --auto-update $filename"
       );
     unlink($filename);

     return !$result;
   }
 }

@ HTTP proxy の作成

PerlHTTP proxy を作ろうとして真っ先に思い浮かんだのは POE だけれど、ちょっとヘビーなので今回は HTTP::Proxy をチョイス。 もともとフィルタリング HTTP proxy を作ることを念頭に置いた Perl モジュールなので今回の目的にぴったり。

1つはまった点といえば、filter の呼び出しがレスポンス全てを取得してからではなく一部分ずつの呼び出しになるところ。その仕様に気がつくのにちょっと時間がかかってしまった。 例えば XML 形式のレスポンスをフィルタしようとしても、普通に HTTP::Proxy を使うと XML の一部ずつがフィルタに渡されるため、XML のパースがうまくいかない。

これについては HTTP::Proxy::BodyFilter::complete を使うことで、まとめてフィルタに渡せるようになった。

@ レスポンスの処理

Twitter のタイムライン取得については P3:PeraPeraPrvXML 形式で取得しているので、そのタイプのレスポンスをフィルタするようにした。

XML::XPath でステータス部分を抜き出して NG 判定し、NG であれば先頭に [NG] を追加する。 これで Twitter クライアント側で [NG] を NG ワード指定すれば、表示されないようにすることができる。

@ bsfilter による NG 判定

NG 判定は普段メールspam フィルタとして使っている bsfilter を使った。 単純に system 関数で呼び出して結果を取得するだけ。

今回は対象がメールではないので --ignore-header を指定。また自動的に学習するように --auto-update を指定。 それと普段メールのフィルタリングに使っているのとは bsfilterデータベースを別にしたいので、--homedir も指定しておく。

@ NG と非 NG の学習。

NG ワードを twitter-NG.txt に、非 NG ワードを twitter-clean.txt に書いて以下のコマンドを実行。

 bsfilter --add-clean --ignore-header --homedir ~/.twitter-bsfilter twitter-clean.txt
 bsfilter --add-spam --ignore-header --homedir ~/.twitter-bsfilter twitter-NG.txt
 bsfilter --update --homedir ~/.twitter-bsfilter

自分の環境 (Debian GNU/Linux sid)では、UTF-8 で書いておいて問題なかった。

@ フィルタリングしてみる

あとは先の proxy を起動し、P3:PeraPeraPrv でプロキシとして localhost:8088 を指定すれば OK。

タイムラインを取得するたびに bsfilter が動いて NG なステータスには [NG] が挿入される。

@ フィルタリングの精度

これについては、まだまだチューンの必要ありかな。

  • 事前の学習データが少ない。
  • --auto-update していることもあり、最初に NG 判定が多いとそちら側に強化されすぎる。
  • 毎回 bsfilter を呼んでいるため、同じステータスが何度も学習される。

まだ使える精度まで上がってないけれど、教師データを増やせばそれなりにいけるかもしれない。

proxy の枠組ができたので、(@~は抜いてから bsfilter に渡すとか、前後の文脈も含めるとか)いろいろ試して遊べそうではある。 別に bsfilter にこだわらず、正規表現による判定などをしてもよいし。

この辺り P3 は Java で書かれているので、プラグインを書いて拡張できるよう将来になると面白いなと思ってみたり。


[ 12月29日全て ]

2008年12月25日 (木)

PlaggerTwitter のあれこれをメールで通知 このエントリーを含むはてなブックマーク

Twitter 上で要チェックなポストは、今年の4月から MAILPIAケータイメール通知するようにしていた(記事)のだが、最近メールが届かなくなってしまった。 フィードを変更してみたりメールアドレスを変えてみたりしたが駄目。 他に良さそうなフィードメール通知サービスが無さそうだったので Plagger を使うことにした。

Plagger は以前途中までインストールしようと思ったのだが、依存 Perl モジュールが多くて途中でやめてしまった。 今回は目的があってインストールするので、頑張ってインストールした。

インストールするホストに libxml2 と OpenSSL が無くて必須モジュールが入らなかったので、これを別途インストールPlaggerSubversion リポジトリの trunk をチェックアウトしてインストール。 依存 Perl モジュールCPAN から。

ケータイ向けにテキスト形式のメールを送る Publish プラグインWeb で見つけたものを流用。まずは以下の3つレシピcron で 10分毎に実行するように設定した。 メールは基本的に Gmail アカウントに送ってフィルタでケータイに転送。 うまくいっている感じ。

@ Twitter リプライをメールで通知

PlaggerTwitter にログインして replies API にアクセスするようにもできるけれどパスワードを書いておきたくないので、先月作成した CGI スクリプト(記事)経由で取得することにした。

  [Twitter]
    ↑
  [replies.atom さらし CGI スクリプト]
    ↑
  [Plagger (cron で 10分毎)]
    ↓
  [Gmail]
    ↓
  [ケータイ]

@ 指定した Twitter-ers のポストのメール通知

Plagger で直接各 Twitter-ers のフィードを取ってこれるけれど、10分毎にアクセスするほどでもないので、Google リーダーTwitter-ers のフィードをフェッチさせてタグでたばねて公開したフィード経由で取得することにした。

Plaggerレシピをいじらないで Google リーダー上で Twitter-ers を追加・削除でき、Google リーダーでもポストを読めるというのが利点。 ポストが少ない Twitter-er のフィードは Google リーダーが巡回頻度を下げるのでタイムラグが大きくなることがあるのが欠点。

 [Twitter]
   ↑
 [Google リーダー]  ← [Web ブラウザ (設定・チェック)]
   ↑
 [Plagger (cron で 10分毎)]
   ↓
 [Gmail]
   ↓
 [ケータイ]

@ twitter検索結果をケータイにプッシュ

外出先などで、居場所やイベントの情報を Twitter でチェックしたい時がある(役に立つかどうかは別として)。 ケータイから定期的に検索かけるなんてありえないので、メールでプッシュしておいて(気がむけば)読むぐらいにしておきたい。 キーワードの設定・管理については、操作・サーバ実装とも楽したい。

Twitter 関連ということで頻繁にケータイでアクセスして画面に出ている MovaTwitter を活用したい。 ということで MovaTwitter のクリボーに「アクセス keyword」と書くことで検索キーワードを指定できるように組んでみた。

 [MovaTwitter クリボー] ← [ケータイ (キーワード書き込み)]
   ↑
   ↑ クリボーのフィードを読んでキーワードを取得
   ↑
 [CGI スクリプト] → [twitter検索]
   ↑
 [Plagger (cron で 10分毎)]
   ↓
 [Gmail]
   ↓
 [ケータイ]

いまさらだけれど、Plagger 便利だな。 とっかかり(インストールと概要理解)がちょっと難しいけれど、それを乗り越えてしまえば Perl なんでどうとでもなるという感じ。


[ 12月25日全て ]

2009年3月13日 (金)

久しぶりの C++GNU Automake + CppUnit このエントリーを含むはてなブックマーク

ちょっとした文字列構文解析関係の C++ コードを書き始めた。 C++ は随分触ってなかったので「C++ で書き直すのを考慮してそれっぽく Perl で書くから後で書き直して」と最初は言っておいたのだが、それもあんまりだと思って C++ で書くことにした。

Debian GNU/Linux 上で書くので GNU Automake + CppUnit で。 「Perl + Test::Harness」や「Java + Eclipse + JUnit」や「C# + Visual C# + NUnit」などと比べるとやっぱりタルいな。

1つメソッド書くのに、

  • テストメソッドの宣言
  • テストメソッドの登録 (CPPUNIT_TEST())
  • テストメソッドの実装
  • メソッドの宣言
  • メソッドの実装

と 4ファイル5カ所編集しなければならない。 クラス追加時には Makefile.am にヘッダファイルとソースファイルをテストケース用のと含めて4ファイル書き加える必要があるし。

あー面倒。

でも C++ で書き始めると楽しいんだよなあ。


[ 3月13日全て ]

2009年8月6日 (木)

今日のさえずり - カレンダーに赤マジックで大きく「KISS このエントリーを含むはてなブックマーク

naney:3796930264

@ 2009年08月06日

  • 08:15 黙祷。 [mb]
  • 08:51 これから区役所行ってくる。 [mb]
  • 09:06 区役所到着。 [mb]
  • 09:11 書類審査中。 [mb]
  • 09:22 受け付けられた。次7F。 [mb]
  • 09:30 7Fでの手続きも終了。 [mb]
  • 09:31 今回は記念品なし。 [mb]
  • 09:42 四季劇場建設状況。 http://movapic.com/...
  • 10:04 今日はヨドバシカメラに生トロが来るらしい。 #Akihabara L:秋葉原 [mb]
  • 10:40 ここ最近ソフトウェア設計・実装をしているので、カレンダーに赤マジックで大きく「KISS」と書いておいた。 *P3
  • 12:00 @Catshop そう、Keep it Simple, Stupid です。ついつい凝って複雑にしてしまいがちなので、目立つところに書いて注意しようかと。 *P3
  • 12:02 別に完成したらチューして欲しいわけではない。 RT @Naney: ここ最近ソフトウェア設計・実装をしているので、カレンダーに赤マジックで大きく「KISS」と書いておいた。 *P3
  • 12:49 「大宇宙ひとりぼっち」をババンと画面に表示して離席している同僚。 *P3
  • 12:59 昼休みに外出すると留守中「今日はヨドバシアキバの日だ」と言われているらしい。 *P3
  • 17:16 歯医者につき、早上がり。無精髭剃り忘れてるな。 [mb]
  • 17:24 生トロ。 L:秋葉原 http://movapic.com/...
  • 17:27 同僚へ。アキヨドの生トロの最終は 17:30 まででした。残念。 #Akihabara L:秋葉原 [mb]
  • 18:19 ヒゲ剃った。これから歯医者行ってくる。 [mb]
  • 19:33 歯医者終了。久しぶりの麻酔注射怖かったー。 [mb]

[ 8月6日全て ]

2009年10月26日 (月)

今日のさえずり - ブックオフのティッシュ配りはウサ耳付けている このエントリーを含むはてなブックマーク

@ 2009年10月26日

  • 08:30 オイルヒーターついにつけた。 [mb]
  • 09:45 @mizu34 まだ室温がある程度あるため今朝はオイルヒーターも消えている時間が長いですが、これからの電気代を思うと恐いです。 [mb]
  • 09:53 今日のブックオフのティッシュ配りはウサ耳付けている。どうしたというのだ? #Akihabara L:秋葉原 [mb]
  • 10:20 ThinkPad X31 が起動ロゴ画面すら出なくて一度バッテリを取り外してリセット。ハードウェア的に限界なのかな。
  • 11:35 iterator 実装するの結構手間なので for_each 実装に切り替える。
  • 12:34 スターバックスタイム。 [Flickr] http://bit.ly/1di7P0
  • 12:34 りんご 柿 6コ 300円。 [Flickr] http://bit.ly/IZaLX
  • 13:03 電池パック SO02 [Flickr] http://bit.ly/33PwYT
  • 13:59 あ、C++ ってメンバ関数本体に内部クラス書けるのか。 #cpp #cplusplus
  • 14:12 C++ メンバ関数本体に書いた内部クラスは、メンバ関数の属するクラスの private メンバへのアクセス権があるので必要な時には使えるな。 #cpp #cplusplus
  • 15:01 港区神明小学校前にあった文房具屋の名前なんだっけかなあ。 RT @lancia_delta16v: 小学校近くに必ずあった文房具屋は、みんなそれぞれに思い出深いはずだ。今でもまだあるのだろうか。
  • 17:28 やっぱり昼カップヌードル1つだとこの時間腹減ってくるなあ。
  • 17:39 我慢できずにちぎれるチョコ&とろけるミルクサンド。
  • 19:27 秋葉原駅前に花屋ないかなあ。ジーンズメイトいらないから花屋欲しい。年に何回か必要になるんだよね。 [mb]
  • 19:48 @tkono1 情報ありがとうございます。 Google マップで見てみました。神田明神下近くにあるんですね。昭和通り側に普段いるのでもう少し駅に近いところにも欲しいです。 [mb]
  • 24:04 ロットリング エスプリミニとエスプリムーブ [Flickr] http://bit.ly/2fjAZW
  • 00:26 @nyafuru こんな時間に掃除?
  • 24:33 2009年10月24日の歩行: 5869歩、4.45km、55分、4.78km/h、消費 218.6kcal、脂肪燃焼 31.3g、3.0エクササイズ。
  • 24:35 2009年10月25日の歩行: 2430歩、1.82km、24分、4.38km/h、消費 85.5kcal、脂肪燃焼 12.2g、1.1エクササイズ。
  • 24:36 2009年10月26日の歩行: 5149歩、3.94km、45分、5.21km/h、消費 202.4kcal、脂肪燃焼 28.9g、2.9エクササイズ。

[ 10月26日全て ]

2009年10月29日 (木)

howm でサブ階層を作ってメモの一部のみを Dropbox で共有 このエントリーを含むはてなブックマーク

howm の良さを見直したところで、howmメモファイルの一部を Dropbox で共有するように環境設定してみた(以下ディレクトリ構造とかは説明のため簡素化しているけれどだいたいこんな感じ)。

@ howm-directory を設定する(今まで通り)

 (setq howm-directory "~/var/howm/")

@ Dropbox 上に howm ディレクトリを作成する

~/var/DropboxDropbox ディレクトリにしているので、その下に howm ファイルを置く場所を用意する。

 mkdir ~/var/Dropbox/var/howm

@ ~/var/howm/Dropbox から ~/var/Dropbox/var/howmシンボリックリンクをはる

 ln -s ~/var/Dropbox/var/howm ~/var/howm/Dropbox

@ howm-directory のサブディレクトリ以下にメモを新規作成できるようにする

C-c , I で名前をつけてメモファイルを作成できるが、これだと howm の日時をベースにしたファイル名自動生成が使えないので手軽さが半減する。

以下の関数を定義して M-x howm-create-interactively-in で howm-directory のサブディレクトリを指定してメモ作成ができるようにした。

 Memo directory: ~/var/howm/

と表示されたら後ろに Dropbox/ と追加して ~/var/howm/Dropbox/ を指定してあげると、そのディレクトリの下(の年/月の下)にメモファイルが新規作成される。 howm-directory を一時的に上書きするという安直実装だが、ちょっと使った感じではうまく動いている様子。

 (defun howm-create-interactively-in (&optional use-current-directory)
   (interactive "P")
   (let ((howm-directory (read-directory-name "Memo directory: "
                                              (if use-current-directory
                                                  nil
                                                howm-directory))))
     (howm-create t nil)))

[ 10月29日全て ]

2009年12月10日 (木)

今日のさえずり - フロスティ食べたい このエントリーを含むはてなブックマーク

naney:4174421200

@ 2009年12月09日

@ 2009年12月10日


[ 12月10日全て ]

2010年2月3日 (水)

今日のさえずり - 合計777円キター このエントリーを含むはてなブックマーク

@ 2010年02月03日


[ 2月3日全て ]

2010年2月4日 (木)

今日のさえずり - Twitter 割引を実施する大井町のすし処さいしょ このエントリーを含むはてなブックマーク

@ 2010年02月04日


[ 2月4日全て ]

この日記のはてなブックマーク数 Add to Google RSS

Process Time: 0.052637s / load averages: 0.14, 0.20, 0.22
nDiki by WATANABE Yoshimasa (profile)
Powered by DiKicker
Base theme by Nana (for tDiary)