Firefox のアドオン PicLens.これはすごい.ぐっと来た.
あまりにぐっと来たので,衝動的にこのサイトでも対応してみた.対応のし かたは以下のページに書いてある.
要は,画像の場所を列挙した Media RSS という XML ファイルを作って, RSS Autodiscovery で見つけさせればよい.うちの Media RSS はこんな感 じになった.
Firefox で PicLens をインストール済みの方は,メニューバーの右側
(Firefox の場合) や ボタンバー内 (IE の場合) にある青い矢印ボタンを
押してみてください.なんかダーっと写真が流れるはず.
(追記・訂正) すみません,当初 Firefox 専用だと思ってこの記事書いてた のですが,実は IE でも Safari でも動くようです.というわけで一部修正.
Storable の互換性の問題 [2006-03-25-3] で「Byte order is not compatible」とか言われるため perl 5.005_03 で使い続けていた tb.cgi だが,さくらインターネットで使われている OS が FreeBSD 6.x になり perl 5.005_03 が無くなったため,動かなくなっていた.というわけでしば らくトラックバックを送ることも受け取ることも,過去のものを表示するこ ともできなくなっていたのだけど,ようやく重い腰を上げて対応することに した.
ここにある「$Storable::interwork_56_64bitをtrue値に設定」は,Out of memory とか言われてダメだった.
というわけでここの真似をして,いったん perl 5.6.2 で読んでから Data::Dumper で Dump して,改めて perl 5.8.8 で store し直すことにし た.
*.stor を *.stor.old にリネームしてから dump.pl,restore.pl の順に 走らせる.一応うまくいったっぽい.
dump.pl:
#!/usr/local/bin/perl5.6.2
use strict;
use lib "."; # 古い Storable 一式をカレントディレクトリに置いた
use Storable;
use Data::Dumper;
$Data::Dumper::Indent = 0;
$Data::Dumper::Useqq = 1;
while (<*.stor.old>) {
my $new_file = $_;
$new_file =~ s/stor$/txt/;
open(NF, "> $new_file") or die;
my $data = Storable::retrieve($_);
print NF Data::Dumper->Dump([$data], ["data"]), "\n";
close(NF);
}
restore.pl:
#!/usr/local/bin/perl5.8.8
use strict;
use Storable;
while (<*.txt>) {
my $new_file = $_;
$new_file =~ s/txt$/stor/;
open(OF, $_) or die;
my ($line, $data);
$line = <OF>;
eval $line;
close(OF);
Storable::store($data, $new_file);
}
いろいろとありまして,しばらく放置しておりましたが,なにやら巷では 「3ヵ月空白があると連続し たブログとは見なされない」という定義があるらしく,まあどうでもい いっちゃどうでもいいのですが,継続は力なりとか唱えながら再開してみま す.
この辺の対策 [2007-05-05-1] [2007-04-30-1] [2007-04-21-1] を入れて以 降 1ヵ月半ほど,コメントスパムは完全にブロックできていたのですが,つ いに来ました.
アクセス元ホストはわりとバラバラな感じ.ただし 6/23 の 8 件はぜんぶ 一緒のところだった.はてさて.
というわけで [2007-04-30-1],まず世の中の CAPTCHA とかではどうやっ ているかというと,どうやらワンタイムトークンとするのが普通らしい.
今回のケースに置き換えると,サーバは計算問題を生成して (これがトー クン),それをサーバ側に保存しておき,ユーザから送られて来た答えと, その保存しておいた問題 (の正解) と照合する.
ということでそれを実装すればよいのだけど,どうもぐっと来ない.なぜぐっ と来ないのか考えた結果,思い当たったのは以下の 2 点:
ぐっと来ないものを作ってもろくなことにならないのでとっとと却下する.
というわけで考え方を変えてみる.要は,投稿のリクエストに関して,
という条件を満たせばよいのかな.これでどうだろう.
実装はとりあえず以下のような感じ.$page_template_default には
<div class="arith"> <br> コメントスパム回避のため,以下の足し算の答えを半角でご記入下さい: <br> $arith_x + $arith_y = <input class="field" name="arith" value=""> <input type="hidden" name="arith_token" value="$arith_token"> <input type="hidden" name="arith_hash" value="$arith_hash"> </div>
を仕込み,これを表示する直前に
my $arith_x = int(rand(9)) + 1;
my $arith_y = int(rand(9)) + 1;
my $accepted_tokens = {};
if (-e $arith_token_file) {
$accepted_tokens = Storable::lock_retrieve($arith_token_file);
}
my $arith_token;
do {
$arith_token = Digest::MD5::md5_hex($logid .
$q->remote_host() .
int(rand(2 ** 32)));
} while (defined($accepted_tokens->{$arith_token}));
my $arith_hash = Digest::MD5::md5_hex($arith_token .
$arith_passph .
($arith_x + $arith_y));
とする.ここでは token ファイルは読み込んでいるだけなのに注意. if ($mode eq "write") { のときの処理は,
my $arith = $q->param('arith') + 0;
my $arith_token = $q->param('arith_token');
my $arith_hash = $q->param('arith_hash');
my $accepted_tokens = {};
if (-e $arith_token_file) {
$accepted_tokens = Storable::lock_retrieve($arith_token_file);
}
if (defined($accepted_tokens->{$arith_token})) {
exit;
} elsif ($arith_hash ne Digest::MD5::md5_hex($arith_token .
$arith_passph .
$arith)) {
exit;
} else {
$accepted_tokens->{$arith_token} = 1;
Storable::lock_store($accepted_tokens, $arith_token_file);
}
とした.
トークンの生成は適当で構わないのだけど,発行済みのトークンで過去に受 理されたもの,および受理される可能性のあるものと重複しないようにだけ は気をつける必要があるので,何かむにゃむにゃな処理をやっている.
うーむ,ちっともお手軽じゃなくなってきた.いろいろ工夫してみたところ で所詮足し算を実行されたら終わりですからね.なんかベクトルが間違って いる気がしないでもない.
現状の問題点:
というか何か根本的に見過ごしていることがあるような気がしてならない…. どんなもんでしょ.
(追記)
2007年05月06日 kazuhooku しょうもないつっこみしてすみません。よっぱらいつつの感想: syncookies のようなゼロ記憶だと難しいのかな。
http://b.hatena.ne.jp/entry/http://www.kagami.org/diary/2007-05-05-1.html
恥ずかしながら syncookies って初耳だったのでちょっと勉強.
なるほど.トークンを乱数を使って作る代わりに時刻を使うことにして,一 定時間経過してたら reject するってことになりますかね.ハッシュ値の計 算に時刻をつっこんでおくことで,サーバ側の保存無しで expire をチェッ クできるところがミソだと理解しました.
「一定時間」をうまく設定してあげる必要があるかも.短いとコメントを書 いているうちに expire しちゃうし,長いとその間は固定パラメータ攻撃さ れちゃいますよね.まあ 1 時間くらいにしておけば実用上十分な気がしま すが.
…というのが SYN cookies の動作を単純にマッピングした場合の話だと思 いますけど,もしかするともっとうまい応用のしかたがあったり…?
というわけで [2007-04-21-1] 一週間ちょい使ってみているのだけど,今の ところ完全封鎖できている.ここ程度の零細サイトであれば,それなりの効 果が見込めると見てよいのではなかろうか.ちなみに一日あたりの攻撃数は, 日によってばらつきというか波があるんだけど,50〜400 程度.
気になるのは,そもそもスパムでないコメントすら一切届いていないことな のだが,まあ普段からコメントを頂くことは稀なのでよしとしよう.
というわけで実装の話.くっつきBBSの $page_template_default に
<div class="arith"> <br> コメントスパム回避のため,以下の足し算の答えを半角でご記入下さい: <br> $arith_x + $arith_y = <input class="field" name="arith" value=""> <input type="hidden" name="arith_x" value="$arith_x"> <input type="hidden" name="arith_y" value="$arith_y"> </div>
みたいなのを仕込み,これを表示する直前に
my $arith_x = int(rand(9)) + 1; my $arith_y = int(rand(9)) + 1;
とする.んで,if ($mode eq "write") { のときの処理として
my $arith = $q->param('arith');
my $arith_x = $q->param('arith_x');
my $arith_y = $q->param('arith_y');
if (!$arith || $arith != $arith_x + $arith_y) {
exit;
}
を加える.実際には単に exit するのではなくて,ログを取るようにしてあ るけど省略.
(追記) はてブでコメントを頂きました.
2007年05月02日 kazuhooku ?arith_x=1&arith_y=1&arith=2 みたいな固定化への対策が望ましいんじゃないかと思った。実質的には「何か」の入力を求めている時点でスパムよけとしては十分だろうけれども
http://b.hatena.ne.jp/entry/http://www.kagami.org/diary/2007-04-30-1.html
まったくおっしゃる通りで,パラメータの意味を理解すれば固定パラメータ による攻撃は可能です.パラメータとして渡すべき「問い」は「そこに書い てある」ので,原理的にはまあ同じことかと思ってたけど,実際の攻撃手順 を考えてみるとそこにはちょっと敷居の差があるかなあと改めて思った.
というわけでちょっくら修正してみようかと思ったのですが,考え始めると いろいろややこしいので,別記事 [2007-05-05-1] で.
コメント欄 (くっつきBBS) に対する SPAM が多すぎて困る.以前いろいろ 試してみたのだが [2006-04-09-2],やはり完全ではない.
というわけで,アクセシビリティは落ちてしまうけど,簡易 CAPTCHAもどき (?) を入れてみた.といっても画像とかを使うのではなくて,単に足し算の 課題を出すだけ.真面目に破ろうと思ったら簡単に破れる類のものである.
で,果たして真面目に破ろうとしてくるスパマーがいるのかどうかに興味が ある.しばらく様子を見よう.
chalow の「Referrer (Inside)」機能を常用している話は以前書いた [2006-05-05-1].
でもこの [YYYY-MM-DD-I] みたいな文字列を書くのって面倒くさくないすか? エディタ上で作業するなら該当記事を探して,日付を確認して,何番目の記 事かを確認して…になるわけだけど面倒くさすぎる.そんなわけで,ブラウ ザで自分のページを開いて clsearch.cgi で検索してコピーペースト…って のが最近の自分的主流なのですが,やっぱり作業は emacs の中で閉じてい る方が楽だ.
とここまで書いて,w3m.el でも使えばいいんじゃね? とか思ったがそれは 気づかなかったことにして,
この [YYYY-MM-DD-I] な文字列を kill-ring につっこむ elisp を書いてみ ました.勢いだけで書いたので処理が汚いのは勘弁して頂くとして,という かあまりテストしてないのですが,一応動いている模様なので貼っておく.
(defvar chalow-date-regexp "^[01-9]+-[01-9][01-9]-[01-9][01-9]")
(defvar chalow-itembullet-regexp "^\t\\*")
(defun chalow-date-to-datestr (str) str)
(defun chalow-kill-datestr ()
(interactive)
(save-excursion
(let ((curpos (point)))
(if (re-search-backward chalow-date-regexp nil t)
(let ((itemnum 1)
(dstr (buffer-substring (match-beginning 0) (match-end 0))))
(goto-char curpos)
(if (not (re-search-forward chalow-date-regexp nil t))
(goto-char (point-max)))
(while (re-search-backward chalow-itembullet-regexp (1+ curpos) t)
(setq itemnum (1+ itemnum)))
(kill-new (format "[%s-%d]" (chalow-date-to-datestr dstr) itemnum))
(message (car kill-ring)))
(message "date not found")))))
Ctrl-S とかで (別に他の何でもいいですが) 該当記事を探して,その記事 の途中のどこかで M-x chalow-kill-datestr すると kill-ring に [YYYY-MM-DD-I] が追加されるので,Ctrl-Y で貼りつけます.
先頭の方の変数とかをいじれば,ChangeLog とは違うフォーマットで書いて いる場合にもある程度適用できるんではないかと思います.(というか私が そうしてます)
* [haepeaodqw] NEW DELHI: Investigators believe an e ma... (2007-11-26 08:47:57)
* [pyfxrshkmn] 1 quarterback before suffering a knee in... (2007-11-25 12:50:43)
* [mvxqgdifga] Dick\'s Sporting Goods said Tuesday that... (2007-11-24 12:01:07)
* [cebcioacfi] Citroen\'s Sebastien Loeb concluded the ... (2007-11-22 15:16:30)
* [fwikcolokt] "Combined with Chrysler\'s Multi di... (2007-11-19 13:44:56)
* ...
最近,copyurl+ とかでページタイトルをコピーしたり,bloglines のアイ テム名をコピーしたりして,そのまま ChangeLog メモに貼りつけている場 合が多い (いったん俺フォーマットを経由してですが).
コピーしたページによっては,タイトルの先頭にカテゴリ名がついている場 合とか (tDiary なんかが典型),ちょっと前に流行った一文字 blog 略号 (?) がついている場合がある.それを ChangeLog メモ記法にそのままコピー して,末尾にカテゴリ名をつけるとこうなる.
* [を] chalow でアスキーアートを表示するためのプラグイン [tech][aa]:
- http://nais.to/~yto/clog/2006-09-23-3.html
これを chalow の ChangeLogReader.pm でそのまま読み込むと [を]〜 [tech][aa] 全体がカテゴリリストと認識されて,ちょっこすおかしなことにな ることに気づいた.
というわけで修正してみる.ややこしいな.合ってますかこれ?
- if ($ih =~ s/\s*\[(.+)\]$//) { # category
+ if ($ih =~ s/\s*\[(([^\[\]]+\]\s*\[)*[^\[\]]+)\]$//) { # category
@cat = split(/\s*\]\s*\[\s*/, $1);
}
ここしばらく,外部に公開する記事しか chalow を通していなくて,外部に 公開する記事の場合タイトルとかは自分で整理し直すので気づいていなかっ た.ふと久しぶりに全記事を chalow に通したら「File name too long」な エラーが出て気づいた.
(追記) 例が適切でなくて誤解を招いてしまったのでちょっと修正.カテゴ リは複数つく場合があるんです.まとめて切り出した後,split する処理が 続いているコードでした.
* [nhbgufaqyn] NEW DELHI: Investigators believe an e ma... (2007-11-26 08:47:56)
* [hzidmxivcg] 1 quarterback before suffering a knee in... (2007-11-25 12:50:42)
* [oqalpvtjdu] Dick\'s Sporting Goods said Tuesday that... (2007-11-24 12:00:46)
* [bvfpsgzbhc] Citroen\'s Sebastien Loeb concluded the ... (2007-11-22 15:16:42)
* [llabydbesb] "Combined with Chrysler\'s Multi di... (2007-11-19 13:44:50)
* ...
ついで [2006-10-08-2] に bloglines アイテムをクリップボードにコピー する方も改版.こちらは bloglines の変更じゃなくて,Firefox の変更に 対する対応になっていると思う.変更箇所は
というわけで以下を bookmark してください.
javascript:(function(){
/*
setClipboard for Firefox
LastModified : 2006-01-10
http://la.ma.la/misc/js/setclipboard.txt
*/
function setClipboard(text){
var url = [
'data:text/html;charset=utf-8;base64,PGJvZHk+PC9ib2',
'R5PjxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij4KKGZ1',
'bmN0aW9uKGVuY29kZWQpe3ZhciBzd2ZfZGF0YSA9IFsKICdkYX',
'RhOmFwcGxpY2F0aW9uL3gtc2hvY2t3YXZlLWZsYXNoO2Jhc2U2',
'NCxRMWRUQjJ3JywKICdBQUFCNG5EUGdZbGpBd01qSTRNejAlMk',
'YlMkY5JTJGZTJaZkJnYUdhV3dNRE1uNUthJywKICdrTU10TjRH',
'ZGdaZ1NJTXdaWEZKYW01UUFFJTJCQm9iaTFCTG5uTXlDcFB6RW',
'9oU0dJJywKICdQRnAlMkZBeHNEREJRa3BGWkRGUUZGQ2d1eVM4',
'QXlqSTRBRVVCaXkwVndBJTNEJTNEJwpdLmpvaW4oIiIpOwpkb2',
'N1bWVudC5ib2R5LmlubmVySFRNTCA9IFsKICc8ZW1iZWQgc3Jj',
'PSInLHN3Zl9kYXRhLCciICcsCiAnRmxhc2hWYXJzPSJjb2RlPS',
'csZW5jb2RlZCwnIj4nLAogJzwvZW1iZWQ+JwpdLmpvaW4oIiIp',
'Owp9KSgi',btoa(encodeURIComponent(text)+'")</'+'script>')
].join("");
var tmp = document.createElement("div");
tmp.innerHTML = '<iframe src="'+url+'" width="0" height="0"></iframe>';
with(tmp.style){
position ="absolute";
left = "-10px";
top = "-10px";
visibility = "hidden";
};
var b;
try { /* modified by swk */
b = top.frames[0].document.body;
} catch (e) {
b = document.body;
}
b.appendChild(tmp);
setTimeout(function(){b.removeChild(tmp)},1000);
}
function extractText(node) {
var text = '';
if (node.nodeType == 3) { /* TEXT_NODE */
text = node.nodeValue;
} else if (node.hasChildNodes()) {
var n = node.childNodes.length;
for (var i = 0; i < n; i++) {
text = text + extractText(node.childNodes[i]);
}
}
return text;
}
function fmt(title, href) {
return '\r\n\t* ' + title + ':\r\n\t- ' + href + '\r\n';
}
var clog = '';
var h3s = top.basefrm.document.getElementsByTagName("h3");
for (var i = 0; i < h3s.length; i++) {
var a = h3s[i].getElementsByTagName("a")[0];
clog = clog + fmt(extractText(a), a.href);
}
setClipboard(clog);
})();
しかしこう bloglines や Firefox に仕様変更がある度に振り回されるのは 何とかならんものか.何か根本的に方針を間違っている気がしないでもない なあ.
* [hghajenjql] Hello! Good Site! Thanks you! <a href... (2008-03-26 10:27:46)
* [xrerxwzuqy] NEW DELHI: Investigators believe an e ma... (2007-11-26 08:48:20)
* [dafbefnmkn] 1 quarterback before suffering a knee in... (2007-11-25 12:50:40)
* [xexongxogy] Dick\'s Sporting Goods said Tuesday that... (2007-11-24 12:01:07)
* [jqbplsmjfo] Citroen\'s Sebastien Loeb concluded the ... (2007-11-22 15:16:22)
* ...
いろいろ文句言いながらも,しつこく bloglines 使ってます.
以前書いた keep new を解除する bookmarklet [2006-07-08-1] が動かなく なっていたので修正.
今までの bloglines では keep new のチェックボックスをクリックすると そのたびにページ遷移が発生していたのだけど,最近 Ajax 対応したらしく ページ遷移しなくなった.というわけで bookmarklet の方で自前で Ajax 化 する必要はなくなって,本家が用意してくれている JavaScript 関数を呼び まくるだけでよい.ずいぶんシンプルになった.
javascript:(function(){
var ipts = top.basefrm.document.getElementsByTagName("input");
for (var i = 0, k = 0; i < ipts.length; i++) {
if (ipts[i].type == "checkbox"
&& String(ipts[i].onclick).match(/markUnreadItem\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,.*\)/)
&& ipts[i].checked == true) {
var siteid = RegExp.$1;
var subid = RegExp.$2;
var itemid = RegExp.$3;
ipts[i].checked = false;
top.treeframe.keepItem(siteid, subid, itemid, false);
}
}
})();
* [vurufqpblh] NEW DELHI: Investigators believe an e ma... (2007-11-26 08:47:58)
* [arlmwsxiup] 1 quarterback before suffering a knee in... (2007-11-25 12:50:40)
* [arblknvufi] Dick\'s Sporting Goods said Tuesday that... (2007-11-24 12:01:07)
* [juvhocnpnf] Citroen\'s Sebastien Loeb concluded the ... (2007-11-22 15:16:39)
* [tdhusrtdcp] Camry drivers have led a total of 165 la... (2007-11-19 13:03:19)
* ...
ソースコードなどを blog などに貼りつけるときにどうするのがよいか,と いう話がちょっと前に話題になっていたりして,その 論点の一つに「横に長すぎる場合」をどう扱うかが挙がっていたりするのだ けど,実は似たような問題はほかにもある.連続するASCII 文字列である.
典型的には,長ーい URL 文字列を表示した場合に,枠からはみ出したり, 枠自体がびろーんと伸びて見ずらくなったりする.といっても Firefox の 場合だけなのだけど.
対策法がこちらによくまとまっている:
ざっくり要約すると,まず Firefox ユーザ側の立場としては,
一方,Firefox を使っているかどうかに関らず,ウェブサイトの運営側の立 場としては,
ちょっとややこしいのは,url_breaker には「A要素のみを処理するもの」 と「全文を処理するもの」という 2 系統があり,さらに「xpi版 (つまり普 通の拡張機能)」と「Greasemonkey版」の 2 系統がある,のだが,それらが 直交していない.えーと,こんな感じ?
| A要素のみ処理 | 全文を処理 | |
| xpi | url_breakerの Ver.0.2.2以降 | 同左 (オプション設定) |
| Greasemonkey | url_breakerの Ver.0.2.1 | url_breaker_plus |
というわけで,実はしばらく前からウェブページ側に仕込んでみている. url_breaker_plus の方です.各 HTML ファイルの body 要素の一番最後辺りに,
<script src="/js/url_breaker_plus.user.js" type="text/javascript"> </script>
と入れる. url_breaker_plus.user.js はこちら. オリジナルのままだと開き括弧 {, {, [ の直後でも改行しちゃって(個人的 に)気持ち悪いので,正規表現を以下のようにちょっと修正して使っている.
// var regexp = new RegExp("([!-%'-/:=\\?@\\[-`\\{-~]|&)");
var regexp = new RegExp("([!-%'\\)-/:=\\?@\\\\-`\\|-~]|&)");
さて,実は長い文字列が横に伸びちゃうのが一番うっとうしいと個人的に思っ ているのは bloglines なのけど,url_breaker の効果は有ったり無かった りでどうも挙動が謎である.bloglines の記事表示が table レイアウトな のが問題なのかも.
* [xuxkbgaayp] NEW DELHI: Investigators believe an e ma... (2007-11-26 08:48:20)
* [ldobiofzlo] 1 quarterback before suffering a knee in... (2007-11-25 12:50:35)
* [xyktjpawdx] Dick\'s Sporting Goods said Tuesday that... (2007-11-24 12:00:43)
* [ebpngyrvzl] Henning Solberg (Ford) retired from sixt... (2007-11-22 15:18:50)
* [mtijoofvrl] Citroen\'s Sebastien Loeb concluded the ... (2007-11-22 15:16:36)
* ...
blog に限らずウェブサイト全般の話やけども, 実名を晒して運営するのか,それともあくまで匿名で運営するかは,
自由だ─────!!
という犬井ヒロシ風の前フリは置いといて,実名サイトと匿名サイトの間の インタフェースには,たまにややこしい場合があるという話.
ここは実名サイトなのでそっち側の立場からの見方だけど,匿名サイトの中 には,たとえば個人的人間関係とかによって「実は誰がやっているか」を知っ ているサイトがあります.そういう場合,そのサイトの記事にリンクを張っ たりトラックバックしたりとかするときに,その文脈によっては人間関係に 関する情報を含んでしまうことがあり得て,結果として相手の素性をバラし てしまうことになるのではないかと躊躇することがあります.
というかその辺に無頓着だったせいでバラしてしまったことが過去におそら く多数あります.すんません.今もやってるかもしれません.
逆に言うと,そういう (つまり個人的知合いの) 匿名サイトの場合,面白い 話があっても,紹介しようかしまいか迷って,どういう文脈で紹介すれば 「安全」か迷って,迷うこと自体が面倒くさくなって結局紹介しないってこ とが割と多いです.いや,それがよいとか悪いとかではなくて,事実そうなっ てますという話なので,ご理解ください.
あと,そもそも実名を隠したいのかどうなのかよくわからなくて悩むことも ありますが,まあそれはそれということで.
(以下やや私信)
というわけで「site:foo.bar.example.com 実名」とかでぐぐったりした形 跡が残っているのは,単に上記のような目的の調査の結果なので,あまり深 く考えないでください.
ついでに書くと,「でもこの人,トップページには名前書いてるよなー」と か疑問に思いました.
(私信おわり)
* [xkrhpcyjaq] NEW DELHI: Investigators believe an e ma... (2007-11-26 08:47:59)
* [yqfhxziqua] 1 quarterback before suffering a knee in... (2007-11-25 12:50:43)
* [xdgtzxaphp] Dick\'s Sporting Goods said Tuesday that... (2007-11-24 12:00:53)
* [gdffrgwlxb] Citroen\'s Sebastien Loeb concluded the ... (2007-11-22 15:16:21)
* [wixsfblexk] Camry drivers have led a total of 165 la... (2007-11-19 13:03:21)
* ...
「画像で取得するAPI」ではてなブックマーク件数をお手軽に表示してみた 矢先なのだが [2006-07-15-3],やっぱりやめた.
はてなが重いときとか反応しないときに,自分のページの表示が影響を受け るのが嫌だってのがまずあるけど,そのときに,あー,俺いまはてなサーバ に無駄に負担かけてるーという罪悪感があって精神衛生上よろしくない. (いや,もちろんトラフィック全体からみると,うちから発生する分なんて 誤差に過ぎないわけですが,単に気持ちの問題なので)
つうわけで真面目にはてなブックマーク件数取得APIを叩いてみることにしたですよ.
やり方はいろいろあると思いますが,定期的に件数を取りに行っておいて, HTML から SSI で include することにしてみた.こんなのを cron で定期 的に走らせます:
#!/usr/bin/perl
use strict;
use XMLRPC::Lite;
my $html_clog_url = 'http://www.kagami.org/diary'; # don't add trailing slash
my $html_clog_dir = '/home/swk/www/diary';
my $hatebu_count_dir = '/home/swk/www/hatebu_count';
my $EndPoint = 'http://b.hatena.ne.jp/xmlrpc';
my @urls = ();
while (<$html_clog_dir/*.html>) {
next unless /\/(\d{4}-\d{2}-\d{2}-\d+)\.html$/;
my $ymdi = $1;
push(@urls, "$html_clog_url/$ymdi.html");
if (@urls == 50) {
&writecount(\@urls);
@urls = ();
sleep(3);
}
}
if (@urls > 0) {
&writecount(\@urls);
@urls = ();
}
sub writecount
{
my ($uref) = @_;
my $map = XMLRPC::Lite->proxy($EndPoint)
->call('bookmark.getCount', @{$uref})->result;
foreach (@{$uref}) {
my $url = $_;
my $count = $map->{$_};
my ($ymdi) = ($url =~ /\/(\d{4}-\d{2}-\d{2}-\d+)\.html$/);
if ($count > 0) {
my $str_count = $count . " user" . (($count > 1)? 's': '');
my $str = << "HTML";
<span class="hatebu_count">
<a href="http://b.hatena.ne.jp/entry/$html_clog_url/$ymdi.html">
$str_count</a></span>
HTML
;
&save_file("$hatebu_count_dir/$ymdi.htmlin", \$str);
} elsif (-e "$hatebu_count_dir/$ymdi.htmlin") {
unlink("$hatebu_count_dir/$ymdi.htmlin");
}
}
}
sub save_file { # from kuttukibbs-1.0rc3
my ($fn, $strp) = @_;
open(F, "> $fn") or die "can't open $fn : $!\n";
flock(F, 2);
print F $$strp;
close F;
}
chalow のテンプレートは,
... <h3 class="subtitle"><TMPL_VAR name=header> <TMPL_VAR name=cat> <!--#include virtual="../hatebu_count/<TMPL_VAR name=ymdi>.htmlin" --> </h3> ...
な感じにする.
* [uboeedmjnb] NEW DELHI: Investigators believe an e ma... (2007-11-26 08:48:20)
* [nwgtzxesqb] 1 quarterback before suffering a knee in... (2007-11-25 12:50:43)
* [fgoavlxizw] Dick\'s Sporting Goods said Tuesday that... (2007-11-24 12:01:02)
* [oyigsruuar] Citroen\'s Sebastien Loeb concluded the ... (2007-11-22 15:16:36)
* [trydkjdjud] "Combined with Chrysler\'s Multi di... (2007-11-19 13:44:55)
* ...
chalow のテンプレートの <h3> の辺りに入れてみた ($item_page_template と $item_template の両方).ちっともブックマークされていないのが火を 見るより明らかになった.
... <h3 class="subtitle"><TMPL_VAR name=header> <TMPL_VAR name=cat> <span class="hatebu"> <a href="http://b.hatena.ne.jp/entry/$clog_url<TMPL_VAR name=ymdi>.html"> <img src="http://b.hatena.ne.jp/entry/image/large/$clog_url<TMPL_VAR name=ymdi>.html" alt="See Hatena bookmark comments"></a></span> </h3> ...
1 件ずつリクエストが発生するのがちょっと微妙かも.はてなサーバ側の負 担も結構馬鹿にならないだろうなあ,などと余計なことを心配してしまうけ ど,こういう API を公開する時点で,その辺の目処は立ってるのだろう.
cf. はてなブックマーク件数取得API: http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%D6%A5%C3%A5%AF%A5%DE%A1%BC%A5%AF%B7%EF%BF%F4%BC%E8%C6%C0API
(追記) やっぱやめた → [2006-07-16-1]
* [ozuiawbrwa] NEW DELHI: Investigators believe an e ma... (2007-11-26 08:48:14)
* [kbfxzafkcq] 1 quarterback before suffering a knee in... (2007-11-25 12:50:35)
* [pxdvfwxyhq] Dick\'s Sporting Goods said Tuesday that... (2007-11-24 12:00:56)
* [wprbloodhj] Citroen\'s Sebastien Loeb concluded the ... (2007-11-22 15:16:18)
* [afhromkaut] Camry drivers have led a total of 165 la... (2007-11-19 13:03:16)
* ...
改版しました [2006-10-08-2]
他人様のコードをいじっているうちに [2006-07-05-2] [2006-07-05-3] 何となく勘がつかめてきたような気が するので,調子に乗って懸案事項に手をつけてみる.
以前,bloglines で表示中の記事のタイトル名,URL をまとめてクリップボー ドにコピーする bookmarklet (Firefox 専用) を書いた [2006-02-11-1] [2006-04-22-1]. これ使うときは,
という流れが多くて,何とかならんかなと思ってたのだ.
というわけでこんな感じ.
onload を使っているので MSIE では動作しないはず.直すのは簡単だと思 うけど,とりあえず放置.
ソース:
javascript:(function(){
function phandler (paths) {
if (paths.length < 1) {
return;
} else if (paths.length == 1) {
top.treeframe.location = paths[0];
return;
}
var p = paths.shift();
var xhr = new XMLHttpRequest();
xhr.onload = function () { phandler(paths); };
xhr.open('GET', p, true);
xhr.send(null);
}
var paths = new Array;
var ipts = top.basefrm.document.getElementsByTagName("input");
for (var i = 0, k = 0; i < ipts.length; i++) {
if (ipts[i].type == "checkbox"
&& String(ipts[i].onclick).match(/markUnreadItem\(\s*(\d+)\s*,\s*(\d+)\s*\)/)
&& ipts[i].checked == true) {
var subid = RegExp.$1;
var itemid = RegExp.$2;
ipts[i].checked = false;
paths[k++] = '/myblogs_subs?ui=1&subid='+subid+'&itemid='+itemid;
}
}
phandler(paths);
})();
期せずして Ajax デビューしてしまった.(XML 使ってないから Aj デビュー か?)
やってることは単純で,keep new のチェックボックスについている onclick 属性から,その記事の subid と itemid を取り出して,それらか らパス名 '/myblogs_subs?ui=1&subid='+subid+'&itemid='+itemid を生成 して,GET しに行っている.
bloglines で実際に keep new のボタンを押した場合は, parent.treeframe.location にこのパス名を直接代入するコードが実行され るのだけど,複数の記事についてこれを単純に繰り返すと,前のやつの読み 込みが終わる前に次のやつを読みに行ってしまってうまく行かない.という わけで XMLHttpRequest を使ってみた.
(open の第3引数を false にすればもっと簡単に書けるかと思ったけど,そ うすると解除がすべて終わるまで操作を受け付けなくなってしまって,使い にくかった)
ついでなので,まとめてクリップボードにコピーする方もちょっとだけ書き 直しておく.以前のは正規表現で無理矢理抽出してたけど,真面目に DOM ツリーをたどるようにした.
ソース:
javascript:(function(){
function setClipboard(text){
/* 省略 (http://la.ma.la/misc/js/setclipboard.txt) */
}
function fmt(title, href) {
return '\r\n\t* ' + title + ':\r\n\t- ' + href + '\r\n';
}
var clog = '';
var h3s = top.basefrm.document.getElementsByTagName("h3");
for (var i = 0; i < h3s.length; i++) {
var a = h3s[i].getElementsByTagName("a")[0];
clog = clog + fmt(a.firstChild.nodeValue, a.href);
}
setClipboard(clog);
})();
ChangeLogメモ以外の形式に変換したい場合は,fmt() の中身を適当にいじっ てください.
chalow では,[2006-05-05-1] のように書くと他の記事が参照できて,逆に 参照された側の記事の一番下には参照元一覧が表示される (デフォルトのテ ンプレートだと「Referrer (Inside)」).後で読むときにとても便利なので 使いまくり.
参照記事に飛ぶ場合は,文脈から飛ぶ先の内容がある程度予測できるのだけ ど,Referrer (Inside) 一覧の方は,クリックしてみるまで内容が分からな い.ここに記事タイトルでも表示されてると便利かな,などとふと思ったの で試してみた.
まず parse_entry() の for ループの中,「ハッシュに格納」と「日付リン ク情報の格納」の位置を入れ換えて,後者を次のように変更.入れ換えるの は,$ent->{$i}{h} を使いたいから.($ent->{$i}{ho} でもいいのかも知れ ないけど,念のため)
# ハッシュに格納
$ent->{$i}{h} = okikae($ent->{$i}{ho});
$ent->{$i}{c} = okikae($c);
# 日付リンク情報の格納
while ($c =~ /\[((\d\d\d\d-\d\d)-\d\d(-\d+)?)\]/g) {
$inside_ref{$1}{"$ymd-$i"} = $ent->{$i}{h};
}
で,get_inside_ref() を以下のように変更.(変わってるのは return map ... の行だけ)
sub get_inside_ref {
my ($id) = @_;
if (defined $inside_ref{"$id"}) {
return map { "<br> " . datestr2anchor("[".$_."]") . " " . $inside_ref{"$id"}{"$_"} }
(sort {$b cmp $a} keys %{$inside_ref{"$id"}});
}
return ();
}
というわけでこんな感じ↓の表示になるはず.これは自己参照だけど.
以前公開して [2006-02-11-1],その後 Firefox 1.5.0.1 だと動かないこと が判明した [2006-03-08-2] bloglines to ChangeLogMemo な bookmarklet ですが,Firefox が 1.5.0.2 に自動更新されてから試してみたところ,普 通に動くことが判明.なんですかこれ.
実はちょうど動かない原因を調査していて,回避策が分かった矢先だった. Firefox のJavaScript コンソールによると,フレームのあるページで document.body.appendChild と document.body.removeChild を呼び出そう とすると
エラー: uncaught exception: [Exception... "Node was not found" code: "8" nsresult: "0x80530008 (NS_ERROR_DOM_NOT_FOUND_ERR)" location: (コード略) Line: 1"]
となっていたらしい.
バグフィクスリストを見ても,とくに該当しそうなものに見当がつかないん だけどな.まいいか.
というわけで,Firefox 1.5.0.1 で動かさない限りは動作は変わりませんが, 一応新しいの置いておきます.
以前のは,sacja TTT-protokolo さんの bookmarklet が元ネタでしたが,上記の原因調査の過程で,そ のさらに元ネタである 最速インターフェース研究会さんの に遡りました.
中身は
javascript:(function(){
function setClipboard(text){
(略)
}
var src = top.frames[1].document.body.innerHTML;
var pat = /<h3><a title=%22.*href=%22(.*)%22 target=%22_blank%22>(.*)<\/a>.*<\/h3>/g;
var clog = '';
var result;
while ((result = pat.exec(src)) != null) {
clog = clog + '\r\n\t* ' + result[2] + ':\r\n\t- ' + result[1] + '\r\n';
};
setClipboard(clog);
})();
setClipboard() の中身は http://la.ma.la/misc/js/setclipboard.txt で す.途中の appendChild, removeChild するところをいじってますが, 敢えて Firefox 1.5.0.1 で使わない限りはオリジナルのままでよいです.
ChangeLog じゃなくて他のフォーマット変換したいときは clog = clog + ... のあたりを適当に.
結論から言うと,敗北です.
kuttukibbs に,できるだけ 簡単な修正を加えるだけでどこまでコメントスパムをブロックできるか試し てみた.
巷でよく行われているのは,「2 byte 文字がいっさい含まれていないもの は無条件で弾く」というもの.日本語サイトの場合,ほぼこれで問題無いわ けなのだけど,なんていうか,ほら,技術的に 負け って感じがする じゃないですか(ぉ.というわけでもう少しギリギリの所で戦えないかと試 してみたかったわけですよ.
戦略は以下の通り:
やってみるといずれもそれなりに有効で,そこそこ引っかかってくれる.最 初の hidden なタグを埋め込んどく程度の低レベルなやつでも,全く無力と いうわけではないみたい.
だけど,ある特定の記事 (具体的には [2006-03-07-2] なのだが) について は,これらをすり抜けて来る奴ら続出.強力なのにマトかけられちゃったっ ぽい.というわけで「この記事限定」で「2 byte 文字が含まれておらず, かつ URL らしき文字列で終わっているもの」はすべて弾くことにした.
一応これでいまのところ完全封殺.なのだけど,勝ち負けで言ったら敗北で すな.
Movable Type とかだと,いったん必ず Preview ページを表示して,そこで hidden なパラメータを配るなんて方法がよく使われているらしい.でも これも対策が取られるのは時間の問題かなという気もする.
結論:
えらく古い話ですが,
可能であれば http://www.example.com/ と http://example.com/ の両方で アクセスできるようにする方がいいし,またその場合は,単に両方の URL でアクセスできるだけじゃなくて,片方に redirect するようにした方が SEO 的によろしいという話.
うちは今までは www.kagami.org でしか答えてくれないレンタルサーバだっ たので気にしていなかったけど,サーバ移転後は kagami.org でもアクセス 可能になった.というわけで .htaccess で
RewriteEngine on
RewriteCond %{HTTP_HOST} sakura\.ne\.jp$ [NC,OR]
RewriteCond %{HTTP_HOST} ^kagami\.org$ [NC]
RewriteRule .* http://www.kagami.org%{REQUEST_URI} [L,R=301]
と設定.
ところで,
「同じ内容を返す URL は常に一つ」という概念のことを“Permalink”といい
http://labs.cybozu.co.jp/blog/akky/archives/2005/12/url_2_www.html
ほんと?
ある URL が指す記事が唯一に定まるのであって,ある記事を指す URL が唯 一に定まるわけではなかろう.それじゃあいわゆる「blog のトップページ」 とか「月ごとページ」とかが存在できなくなっちゃう.
というか,URL が唯一じゃないから,そのうち 1 つを選んで「これが permalink ですよ」と明示する必要が生じるわけで,むしろ「同じ内容を返 す URL が唯一ではない」(かつそれら複数の URL の中には,今後同じ内容 を返すとは限らないものが含まれている) ことが permalink という概念が わざわざ発生した前提になっているといえるんじゃないかな.
というわけで,この話と permalink は無関係だと思うのです.
今まで使ってたメイルネットのサーバでは perl 5.005_03 (i386-freebsd) が使われていた.モジュール群はあまり揃っていなかったので,必要なもの は ~/lib/perl に自分でインストールして使っていた.
さくらインターネットでは,/usr/bin/perl は v5.8.4 (i386-freebsd-64int).モジュールもそこそこ揃っている.これなら自前で モジュールをインストールする必要はないかなと思っていたけど,甘かった.
Storable に互換性がない.
tb.cgi では,トラックバックのデータの保存に Storable が使われている. そのデータが読めなくなってしまった.Storable::retrieve が「Byte order is not compatible」とおっしゃっている.うーむ.
幸い,さくらインターネットのサーバには perl 5.005_03 built for i386-freebsd も /usr/bin/perl5 としてインストールされているので,こっ ちを使うことにした.こっちのバージョンではモジュールがあまり揃ってい ないらしい.というわけでメイルネットのサーバで使っていた ~/lib/perl 以下をごっそりコピーして使うことにする.再コンパイルとかせずにそのま まで動くのはありがたい.
他の CGI (clsearch, kuttukibbs, noascii) は perl v5.8.4 で問題なく動くようなのでそちらで動かす.ただし use lib で ~/lib/perl を指定しているとモジュールの互換性の問題で動かないので, 指定を止める.
とりあえずはこれでいいけど,いつまでもこのままってわけにもいかないか な.過去データをまとめて新しいファイル構造に変換して,v5.8.4 に移行 するようにした方がいいかも知れない.調べてみると,Data::Dump を使っ て一旦テキストとして吐き出させるという方法があるらしい.そのうち試し てみるか.
おまけ.というかちょっとだけはまった落とし穴.
さくらインターネットのサーバには,以下の 2 種類の perl がインストー ルされている.
そして以下のような symlink がある.
/usr/local/bin/perl5 は 5.005_03 を指しているのが自然だよなあ.どう してこんなことになっているんだか.
* [かがみ] なるほど,そうかも知れませんね.しかしそうだとすると /usr/bin/perl... (2006-03-27 04:45:47)
* [otsune] >どうしてこんなことになっているんだか.おそらく、/usr/local/b... (2006-03-26 21:21:18)
今まで使っていたレンタルサーバの契約 (年更新) が来月切れる.ちなみに ここ:
メールサービスだけ 4 年前に使い始めて [2002-04-19-1],その後 1 年ちょっ と前からウェブを使い始めた [2004-11-14-2].そして現在,ウェブ容量の 50MB はだいたい使い切りそうな状態に至っている.容量の大きなコースは, 競合他社と比べてあまりに割高だ (まあ現コースもだけど).
というわけで,他社サービスに乗り換えることに決めました.メイルネット さん今まで大変お世話になりました.
移転先はさくらインターネットのスタンダードプラン (http://www.sakura.ne.jp/).以下のような辺りが決め手となって選んだ.
最初の 2 つは,まあ個人的な趣味.やっぱり使い慣れている環境に近いの はありがたい.3 つめは直接的な要因ではないけど,ちゃんとした (?) ユー ザ層に支持されているんだなあというのが伝わって来て,決心が後押しされ た感じ.
設定の話.ウェブ関連の修正は以下の通り.
最後の CGI 関連についてちょっと補足説明が必要だと思うけど,長くなる ので別記事で[2006-03-25-3].
というわけで,この辺を変更して動作が確認できたので,旧サーバのコメン トとトラックバックを停止 [2006-03-25-1] して,DNS 情報を更新.新しい 情報が伝播して新サーバにつながるようになれば,コメントとトラックバッ クも復活したように見えるという寸法.もしこの記事が読めているのであれ ば,新サーバにつながっているはずです.
メールの方は,単に同じ名前のアカウントを作るだけで,何の苦労もなく移 行できた,はず.
メンテナンスのため一時停止します.
(追記) 再開しました.たぶん.
新しくなりました.こちらへ [2006-10-08-3].
bloglines で開いているフィードのアイテムをごっそり ChangeLog 形式に 変換して,クリップボードへコピーする bookmarklet を書いてみた. ただし firefox 専用.
書いてみたというか,下記の「ページタイトル+選択文字列+リンクを clipboardにコピーするbookmarklet」をちょっと書き換えてみただけです. bl2clog() って関数が新しいところで,他はほとんど同じ.
bl2clog() の中の clog = clog + ... のところをいじれば,違う出力フォー マットにも簡単に対応できるはず (実際,自分では ChangeLog とはちょっ と違うフォーマットでメモを取っている).
JavaScript は読むことも書くこともできないので,なんか変なことやって る可能性大.実際,正規表現で力まかせに処理しているのがちょっとダサい 感じ.bloglines のページ構成が変わったらアウト.もっと真面目に element や attribute を抽出するのが正しいんだろうなとか思うのだけど, まあ当面はこれでいいか.
最近は,気になったアイテムはとりあえず keep new しておいて,時間があ るときにまとめて読むことが多いんだけど,ふと気づくと数十個 keep new されていて自分のメモに転記するのも億劫になってしまう(で,さらにたま る).というわけで,keep new なものをまとめて自分メモに変換する手段が 欲しかった.
ついでに keep new の一斉解除もできるといいんだけど,どうすればいいの かな… (追記: できました [2006-07-08-1])
(追記) Firefox 1.5.0.1 だと動かないようです [2006-03-08-2].付け焼き 刃なのでどこをどう直せばよいのかさっぱり分かりません…
(追記) Firefox 1.5.0.2 だと普通に動くようです [2006-04-22-1].なんだ かさっぱり分かりません.
ごあいさつ文化圏から spam 文化圏への矢印は,ちょっとカルチャーショッ クかも.
ちなみに私の場合は,他の記事に言及した際に,その元記事の筆者に積極的 にフィードバックしたい内容があるときだけトラックバックを送信すること にしてます.まあ面倒くさいからってのが大きいけど.あと送信先の空気も 読むけど.
トラックバックをもらった場合の対応は,(少なくとも今のところ)もらうこ と自体があまりないので,別に考えてません.
はんげ …って何だろう?
とナチュラルに思いました.私だけですかそうですか.
やろうやろうと思ってて放置していた.本当は受付時に処理するのが正しい と思うのだけど,とりあえず表示時で対応する.tb.cgi の sub enc の定義 を除去して,代わりに以下を挿入.
my $enc_maxlen = 512;
sub round_utf8 { # http://www.akatsukinishisu.net/itazuragaki/id/round_utf-8.html
my $str = shift;
return $str if ($str =~ /[\x00-\x7F]$/);
$str =~ s/[\xC0-\xFD]$//;
$str =~ s/[\xE0-\xFD][\x80-\xBF]$//;
$str =~ s/[\xF0-\xFD][\x80-\xBF]{2}$//;
# $str =~ s/[\xF8-\xFD][\x80-\xBF]{3}$//;
# $str =~ s/[\xFC-\xFD][\x80-\xBF]{4}$//;
$str;
}
sub enc {
use Jcode;
my $str_orig = $_[0] ? Jcode->new($_[0])->utf8 : $_[0];
my $str = &round_utf8(substr($str_orig, 0, $enc_maxlen));
if ($str ne $str_orig) {
$str .= " ...";
}
return $str;
}
utf8 の末尾切り落とし処理はぐぐって見つけたものを頂きました.自分で は理解してませんのでそのままこぴぺしてます.
chalow に付属する検索 CGI の clsearch.cgi が,いつの頃からか詳細モー ド ($mode == 1) だと記事タイトルや日付を表示してくれなくなってて, あれ? とか思いつつ放置していた.
で,ふと思い立って中身を読んでみたところ,ページの最小単位が日ごとか らアイテムごとに変わったときの副作用だと理解した.
詳細モードの動作は,
となっている.日ごとページから抜き出していたときは記事タイトルが start: 〜 end: 間に含まれていたけど,アイテムごとページの場合,デフォルト のテンプレートだと記事タイトルは <h1>〜</h1> の方にあるので,結果と して記事タイトル無しのまま抽出されて並ぶことになる.
というわけでアイテムページのテンプレートでも,start: 〜 end: 間に記 事タイトルとかを書いてやるようにすれば,clsearch.cgi はちゃんと表示 してくれる.<h1>〜</h1>の方はどうしましょうかね,と思ったけど,両方 に書いておくことにした.ちょっと変かな.まあいいよな.
さて日付はどうしよう.というか仕組みを考えると,アイテムごとページが 導入される前から日付は表示されていなかったってことになるな.よく覚え てないけど.一番簡単なのは,start: 〜 end: 間に日付も入れてしまうっ て方法かな.
<!-- start:<TMPL_VAR name=ymdi> -->
<div class="day">
<h2><span class="date"><a href="<TMPL_VAR name=ymd>.html">
<TMPL_VAR name=ymd></a></span></h2>
<div class="body">
<div class="section">
<h3 class="subtitle"><TMPL_VAR name=header> <TMPL_VAR name=cat></h3>
<TMPL_VAR name=content>
(中略)
</div><!-- section -->
</div><!-- body -->
</div><!-- day -->
<!-- end:<TMPL_VAR name=ymdi> -->
start: 〜 end: の意味を変えちゃうのでちょっと危険な香りもする.日ご とページの方の start: 〜 end: と構造が変わっちゃうし.これが嫌な場合 は clsearch.cgi をいじるしかないかなあ.
(実は最初は clsearch.cgi をいじってたんだけど,結局元に戻して以上の ような対処に落ち着いた)
chalow で %all_entries をキャッシュするようにしたら高速化できないか な,とふと思って,とりあえずやってみたけど 40 秒 → 30 秒程度だった. 残りの内訳は HTML 生成ループと write_*_page 群がそれぞれ 10 秒強って 感じ (← コード書く前に計れと小1時間).やはりそっちもキャッシュしな いとダメか.それはめんどくさそう.
カレンダーとか月別リストとか inside refer とか same day とかは, JavaScript のくっつきなり SSI なりとしてファイル分離するのが正しいの かなあとか漠然と思った.
--stop-date でいいじゃんと言われるとそれまでなんですけどね.なんとな く,あの敗北感がいや.
ブログデザインの間違いトップ10.
ふーん,そんなもんなのかな.よく分からんけど.
とりあえず,
5. Classic Hits are Buried
これは趣旨が理解できた.よく考えると,そもそも自分が書いた記事ごとの アクセス数の分布ってちゃんと見たことなかったな.
というわけで手抜きワンライナーを書く.
% ( cd /path/to/chalow_output/; awk '{print $7}' /path/to/apache_log_archive/*.combined_log | egrep '^/diary/....-..-..-[01-9]+\.html"' | sort | uniq -c | sort -rn | sed 's#/diary/##' | sed 's/"//' | awk '{print $2}' | xargs grep '<title>' | sed 's/:<title>/ /' | sed "s# - swk's log</title>##" ) | less
まあこんなもんかな.タイトル表示とアクセス数の表示が一緒にできるとい いけど,ワンライナーだと難しいかな.
というわけで,この手抜き状態のまま加工して,サイドバーに「アクセスの 多い記事」一覧として埋め込むことにしてみました.1 週間ごとに更新され ます (サーバのログが 1 週間ごとにしか手に入らないので).
ネタバレ記事を書くのをどうしようかと悩んでいたわけなのだが [2005-10-20-2],まあいいやということで,ごく普通にテキストと背景の色 を同じにして書いてみた[2005-10-21-2].しばらくして
RSS リーダならそのまま読めてしまう
ことに気づいた.のわー.読みたくないのに読んじゃった人ごめんなさい.
応急措置ということで,chalow の write_rss_file() の中に
$coen =~ s!<img src="([^h].+?)"!<img src="$clog_url_pref$1"!g;
+$coen =~ s!<div class="hidden">.*?</div><\!--hidden-->!<div>\(hidden\)</div>!gsm;
my $cont = $all_entries{$ymd}{$i}{c};
+$cont =~ s!<div class="hidden">.*?</div><\!--hidden-->!<div>\(hidden\)</div>!gsm;
$cont = html2xmlstr($cont);
な処理をつっこんで,ネタバレ部分を
[esc]<div class="hidden">[/esc] はうン [esc]</div><!--hidden-->[/esc]
な感じで囲んでおくことにする.うーん,アドホック.
まあ,そもそもビジュアルでないブラウザの人や CSS 切ってる人は読めちゃ うわけですが.前回も書いたけどどうしたものか.
えーと,vi の話の件ですが [2005-08-28-1],ここのアクセスログは 1 週 間ごとにしか見れないので全然気づいてなかったんだけど,blogmap に載っ てるよとか yendot に載ってるよとか教えられて,ようやく状況に気づきま した.
つうかどっちのサイトも初めて知りました,すんません.何かトラックバッ クが妙に多いなとは思ってたのですが.
リンク元をいろいろ見て回ると,引用ばかりで読みにくいという指摘なども 頂いていたりして,実際おっしゃる通りなわけです.もう少し読み手のこと を考えて書くべきなのかなあとも思うのですが,あまりそんな文才も余力も ないので,まあ当面は今まで通りマイペースで,自分用メモの延長ってこと で書いていきます.
関連しつつちょっと脱線しますが,「引用だけ」てのは「そもそも引用とは 認められない」かも [2005-06-13-1] って話もあるので,ちょっと考えねば ならんのは確かなんですよね.
でも,「ささっと取ったメモ」を「as is で公開する」ことによる情報の流 通ってのも,いわゆる blog の重要な側面な気はするんです.誰かの権利を 侵害しているのでない限り,あまり杓子定規に著作権法とか考えてても生産 的じゃないと思うので.んー,もしかして自分で気づいてないだけで何か侵 害してます?
あと,見ずらい一因は,blockquote な部分と,そのネタ元の URL を書いて る部分が分離している点にもあると思うので,そこは何とかしようと思って ます.これは,プレインテキストで書き続けて来たメモを chalow で公開す るようになる以前からの書き方を,そのまま踏襲していることによります. [category: logging]
他人事だと思ってた Musical Baton が回ってきた. まあ chain mail みたいなもんだからいつかはやってきても不思議はないん ですが.
ん,musical button なの? ずっと baton だと思ってた…ていうかやっぱ baton が正しそうじゃん.まあどっちでもいいけど.
古い人間なので電子ファイルではあまり持ってません.試聴のために取って 来て,そのまま残っているものがポツポツとある感じ.しかも ls *.mp3 す ると,なんか perry.mp3 とか harada.mp3 とかが混ざってて正確に計測で きないんですがどうしましょう.まあ面倒なんでそういうのもひっくるめて 測りましょうか.
% ls -l *.mp3 | awk 'BEGIN{s=0}{s += $5}END{print s}'
64263257
というわけで 64MB.
ちなみに一番小さい音楽ファイルは napalm_death-you_suffer.mp3 で 100KB.演奏時間 5 秒 (そのうち無音部 4 秒).
「ちょうど今」というのを「baton を渡された記事を読んだ瞬間」だとす ると,何も聴いてませんでした,ってのが答えです.これだけとつまんない ので,そのとき CD ドライブに入ってたのを見るとこれでした.
これを書いてる今聴いてるのはこれ↓だったりしますが,まあいくらでも恣 意的に選べるから (要するに,聴くもの選んでから書けるから) 面白くない よね…
Zero Hour / The Towers of Avarice
Amazon で予約して購入.
あ,アルバム 5 枚じゃなくて 5 曲ですか.難しすぎ.いや 5 枚でも難し いけど,さらに難しすぎ.
「よく聴く」ってのはその時期によって変わるので思い入れの方でいきます か.悩ましいけど悩んでもしかたないのでざっくりと.
ここを読んでそうでかつ blog 書いてそうな知人の心当たりがほとんどあり ません.ヒロシです…
んーと,
まずは,その数少ない心当たりの 2 人に:
次に,面識はないのですが,時々引用してくださる chalower で,ま だバトンが来てなさそうな方に勝手に渡してみます:
ラスト,ここは読んでないと思うけど学生時代のサークル関係へ投げてみる. 音楽人脈を生かした,濃い方面への baton 渡しを期待します:
だいぶ前にいじった気がするけど,書き忘れてたので思い出しながらメモし ておく.
月ごとの日付一覧をカレンダ風に表示するときに,ちまたの blog ツールだ と,前月や翌月へのリンクが表示されていたりする.無きゃ困るわけでも, あるとすごく便利なわけでもないけど,何となく欲しくなったのでつけてみ た.もうちょっときれいに作れたかもしれないけど,とりあえずこんな感じ. chalow-1.0rc4 がベース.
まず
### HTML ファイルの出力 write_index_page();
の直前に
my @month_array = sort keys %month_page;
my %month_array_rev = ();
for (my $i = 0; $i < @month_array; $i++) {
$month_array_rev{$month_array[$i]} = $i;
}
を入れる.同じようなものを write_month_page でも作っているので実は二 度手間.ここで作ったものを write_month_page でも使うようにすればいい んだけど,面倒なので放っとく.
次に make_calendar_table 内の
my @wn = ("Su", "Mo", "Tu", "We", "Th", "Fr", "Sa");
の直前に,
my $idx = $month_array_rev{$ym};
my ($link_before, $link_after) = ('<<', '>>');
if ($idx > 0) {
$link_before =
'<a href="' . $month_array[$idx - 1] . '.html"><<</a>';
}
if ($idx < @month_array - 1) {
$link_after =
'<a href="' . $month_array[$idx + 1] . '.html">>></a>';
}
を入れる.
同関数のヒアドキュメント内で
<caption><a href="$ym.html">$ym</a></caption>
の代わりに
<tr> <td align="center" colspan=2>$link_before</td> <td align="center" colspan=3><a href="$ym.html">$ym</a></td> <td align="center" colspan=2>$link_after</td> </tr>
とする.以上.
しかしアレだ.自分仕様パッチが複数の改造目的から成り立っていると,そ のうち一部の目的のものだけ切り出して配布するってのが面倒だな.各要素 ごとにオリジナルからのパッチの形でまとめて,かつそれらを順不同で適用 できるように直交化しておく…とかできると理想だけど,そういうの自動化 できたりしませんか.つうかできたら cvs の手動マージ機能とか要らないっ て話ですかそうですか.
はっとさせられたのはこれだ.
著作権法で認められるところの引用とは、何か本人が主張する主体部分の文 章があって、それを補足するための「従」であることが前提となっている。 主体がなく、ただ抜き出しただけでは、引用とは認められないのである。
んーと?
(著作権法 第三十二条) 公表された著作物は、引用して利用することが できる。この場合において、その引用は、公正な慣行に合致するものであり、 かつ、報道、批評、研究その他の引用の目的上正当な範囲内で行なわれるも のでなければならない。
blog における「公正な慣行」てのが確立してないのが難しいところかな. いずれにせよ,その引用する目的がはっきり分かるようでないと,「引用の 目的上正当」かどうかは判断できないので,その点ははっきりさせる必要が あるのは確かかも.
法的なことはともかくとしても,自分がどう考えたか,何を思って引用した かは記録しておく価値があるのは確かかも知れない.たとえそれが「私的な 備忘録」だったとしても.まあついついコピーペーストしてそのままにしちゃ うんだけど.
今まで使い続けていた 1.0rc2 から更新.自前の改造パッチもだいたい当て 終えたはず.
カテゴリリストや最近の記事などは,JavaScript feed ではなく静的に挿入 されるように変わっている.実は rc3 で既に変更されていて私が知らなかっ ただけのようだ.じゃあ自前の改造 [2004-11-14-1] は捨ててもいいかな, と一瞬思ったけど,カテゴリ順序の制御とか,<ul> や <dl> によるリスト への変更とかをどうやって本家ロジックに組み込むかを考える気力がなかっ たので,自前改造をしばらくは生かし続けることにした.本当はできるだけ 本家に追従した方が,後々楽なんだけど….
今回の目玉はアイテムごとページを出せるようになったことだと勝手に思っ てるんだけど,その実装のしかたにちょっととまどった.あれー, $item_template が適用されないのはどうして?
で,よくよく考えてみたのだが,$item_template は アイテムのタイトルと かを含んだ "section" div まるごとになっているため,それと互換性を保っ たままアイテムごとページに使うことはできない (例えば,$item_template では h3 になっているものを,アイテムページで h1 にするのは困難) とい うことなのだと理解した.継続してソフトウェアをメンテナンスすることの 大変さを改めて思い知った(つもり).
まあ昔から SPAM はいっぱい来るんだけど,最近は特に日本語のが増えた. アダルトサイトとか,あとは女の子個人を装ったやつとか.出会い系の掲示 板で見てメールしました,みたいな.書き込んでない書き込んでない.
どうもここにログを公開してから増え始めたような気がする.気のせいかも 知れないけど.というわけで,とりあえず各ページに含まれているメールア ドレスをちょっとだけ偽装することにした (「@」→「 _at_ 」).どのくら い効果があるかは不明だけど,結構よく見かけるので,それなりに効果があ るのではなかろうか.
あと,procmail のルールをちょっとアグレッシブなものに変えてみた.ど んな変更かはまだ伏せておく.効果があったら報告したい.しかしこういう 対策ルールが広まると,送り側もそれを避けようとするからなあ.結局いた ちごっこに….
[2005-01-10] の tb_standalone 導入時のメモ.
まずくっつきトラックバックのページの通りにインストール.ただし SSI 化するため,js ファイルではなくて htmlin ファイルを作って,数字のみ を書くように変更.あと,同じ変更を $mode eq delete の場合にも入れる. (でないと削除した場合に数字が変わらない)
うちのサーバだと perl module が足りなかったり古かったりで動かない. 以下を make して,ユーザスペースに置いておく.tb.cgi の先 頭で use lib "/path/to/libdir"; しておく (デフォルトの CGI.pm が古いので, ユーザスペースに入れた方を優先する).
perl module (*.pm) だけじゃなく,loadable object (*.so) も必要なのが 悩ましい.たまたまサーバと同じ OS 環境が手元にあったから,手元でコン パイルしてアップロードするという手が使えた.綱渡りだなあ.
DataDir と RSSDir は / で終わらないとダメなので注意.NotifyEmail は, 不要なときは空文字列にしておけば無視される.
送信が誰でもできるのは,踏台にされたりしそうでいやなので,send_form と send_ping は is_logged_in() が真のときしかできないようにしておく. あとは,list mode の出力スタイルをちょっといじったりとか.
一応動くようにはなったけど,list mode の出力が utf-8 なのがあまり気 に入らない.他のページは EUC-JP なのでそれに統一したいなあとか思って みたり.
というわけで,trackback と文字コードの話をちょっと勉強してみた.
ふむ,trackback の仕様上は文字コードの規定はない.慣習上は送信は utf-8 で,受信は charset パラメータを見るか,自動判定するからしい.
一般に HTTP の user agent は form を送信するときにどの文字コードで送 るか? form 要素に accept-charset 属性が指定されていないときは,デフォ ルト値 UNKNOWN であり,UA はこれを「form を含む文書が送信された charset」と解釈してよい (may).とされている.あくまで「してよい」な んだよな.ほとんどの UA はこの慣習に従っている.でも lynx はダメ(し かも accept-charset も無視する)らしい.そうか,lynx は form 送信には 使わないほうが安全なんだな.メモメモ.
ていうことは,list mode だけ EUC-JP に変換して表示するとかってのは問 題なくできそうな感じ.そのうち気が向いたらやろうかな気味.
くっつき BBS を SSI (server-side include) 化してみた.ってもしかして 既に「くっつき」と呼べなくなってますか? 作者さんに怒られそうだ….一 応このような改造をしようと考えた理由を議論しておこう.
一言でいうとページ表示の速度改善が目的.もちろんメリット・デメリット があって,このサイトにとってはメリットの方が大きいと判断したというだ け.
まずメリット: くっつき BBS が採用する CSI (client-side include) だと, include ごとに js ファイルを取ってくるための HTTP request/response が発生する.大抵は日ごと,あるいは記事ごとに include する使い方なの で結構な数になる.ブラウザがそれらを受け取ってレンダリングを完了する までユーザは待たされる.レスポンスの悪いサーバだとこれがかなりいらつ く.SSI 化すればこの点が改善される.(というわけなので,インライン画 像などをいっぱい貼っているサイトだと,いずれにせよ HTTP トラフィック が多数発生するので,改善率は低いと思う) あとは当り前だけど, JavaScript が使えないクライアントでも大丈夫.
逆にデメリット: サーバに HTML ファイルを parse するための負荷をかけ てしまう.HTTP のハンドリングよりこっちの方が遅い状況だと,上記メリッ トが完全にスポイルされる.でも普通に考えて,かたや system call をば りばり呼び出すネットワーク処理,かたやユーザ空間で閉じた単純な文字列 マッチング,後者の方が重いという状況は限られていると思う.よっぽどで かいファイルで,かつ含まれている include の数が少なかったりするとこ れが起きるかな. あとはこっちも当り前な点として,そもそも SSI が使え るサーバじゃないと使えない.
というわけでケースバイケースなんだけど,うちの場合は明らかに SSI の 方が向いている.ちゃんと測定してないけど体感速度で 1 桁は違う感じ. 結果として,javascript feed は一切なくなりました.今後どうなるかわか らないけど.
変更点としては,kuttukibbs.cgi の中で js ファイルを書き出すところで 生 HTML も別ファイルに書き出すようにしておいて,呼び出したいところで <!--#include virtual="..."--> するだけ. 注意点としては
<!--#config errmsg="" -->
を入れておくってのがミソ.これがないと include するものがないときに エラーメッセージが表示されてうっとうしい.
chalow アンテナに捕捉して頂きました(ありがとうございました).
それはよいのだが,見てみると何やらだーーーーっと数字の羅列が….あー, カレンダー (day_list) が表示されているのか.しかも SMTWTFS という謎 な文字列から始まって,1 から 31 まで各 1 行ずつ….どうやったら表示 されなくなるのか他の人の書き方を見比べてみたけど,何だかよくわからな い….
と思ってたら,どうやら「更新チェック範囲」というのを,アンテナ編集作 業の一環として指定できるというからくりらしい.ということは捕捉される 側としては特に何も気にしなくてよいってことですかね.
でもあまりにも見苦しくて申し訳ないので,カレンダーはサイドバーにでも 入れておくことにしてみた.さてどうなるかな.