2007/08/26

[技術系]   The GUI Loftが消えてる

at 11:31JST
ActivePerl用のWin32::GUI::Loftと、そのGUIビルダーセット。公開サイトがここ数日音信不通だ。消えちゃったのかな。ppmのアーカイブにも登録されてないから入手できない。

http://www.bahnhof.se/~johanl/perl/Loft/

OSSはこういうとこ不便だ…(とOSS信者に叩かれそうなことを言ってみる)。

2007/08/23

[技術系]   ErrorDocumentを絶対URLで書くのはやめようよ

at 13:08JST
紹介されているエラーページのデザインはおもしろい。でも、設定のしかたがよくないと思う。このやりかたは多くのサイトで採用されているようだけれど、はっきりいって迷惑。

404エラーをデザインする為のインスピレーション*ホームページを作る人のネタ帳
http://e0166.blog89.fc2.com/blog-entry-262.html
ErrorDocument 403 http://e0166.com/403error.html
ErrorDocument 404 http://e0166.com/404error.html
ErrorDocument 500 http://e0166.com/500error.html
赤い字で書かれた部分はもちろん皆様のドメイン名に変更してください


これじゃ
「リダイレクトされちゃうからダメ」
だよ。

こういうふうに設定されていた場合、たとえば、
 http://e0166.com/no_such_a_document.html
という、存在しないドキュメントにアクセスすると、

  1. ブラウザはhttp://e0166.com/404error.htmlを表示する
  2. ブラウザのアドレス欄はhttp://e0166.com/404error.htmlに変わる

というふうになる。1はいいのだが、2が迷惑。

「アドレスを打ち間違えた」ためにこのエラーが発生した場合のことを想定してみてほしい。こうした場合、ふつうブラウザの「戻る」で戻ってアドレスを打ち直そうとするのが人情だが、

  • 戻ると、またリダイレクトでエラーページにジャンプさせられる
  • 「じゃあ戻らないで打ち直そう」と思っても、アドレスがエラードキュメントのアドレスになってしまっているので打ち直しづらい

といった感じで、実は不親切このうえない。

おまけに
「HTTPのステータスコードが、404 Not Foundではなく302 Foundになってしまう」
ので、ほかにもいろいろ不都合の発生することが考えられる。つまり、サイト運営者の自己満足に終わり、害さえ及ぼす可能性があるわけだ。

こういうことになるのは、ErrorDocumentに対して
「ホスト名まで含む“絶対URL”を指定している」
からだ。そもそも他ホストにジャンプさせたいならともかく、同じホスト上のドキュメントを参照するのに絶対URLを指定する理由などない。

先に挙げたようなめんどうを起こしたくないなら、

  1. 設定時に、
    ErrorDocument 404 /404error.html
    というように、ホスト名を除いたドキュメントのパスを指定する
  2. 404error.html 内のリンク・画像指定のパスはすべて絶対パスで書く

ようにする。こうすると404エラーが起きたときもブラウザのアドレス欄は「間違ったアドレスのまま」保持され、なおかつブラウザには404error.htmlの内容が表示される。

2.は、ブラウザが「間違ったアドレス」のパスからHTMLを解析して表示しようとするから。相対パスで画像を参照したりしているとのきなみ表示されないので注意。

つーことなので気をつけましょう。

Apacheでの話でした。ぼくは1.3系列だけど2系列でも同じはず。どっちにしてもここらへんはマニュアルにぜんぶ書いてある。なにか設定する際は信用ならないblogのエントリ(=このめも含む)など鵜呑みにせず
「自分でマニュアルをよく読もう!」
ということで。

参考:
http://httpd.apache.org/docs/2.2/ja/mod/core.html#errordocument

[技術系]   Windows Live Writer用の「定型文」挿入プラグイン

at 12:36JST
ブログの編集操作が苦手な人でも簡単に記事作成!「Windows Live Writer Beta 2」を試す
http://bb.watch.impress.co.jp/cda/special/19110.html

Windows Live Writerは、かなりデキがいい。ヒトに勧めるならコレだな、と思っているのだけれど、

今のところ文字サイズの変更はできないようだ


と言われてビックリ。確かめてみると、ホントにそういう専用のボタンはない。フォント指定でポイント単位の変更はできるのだが、Wordみたいに大小に変えるボタンはないのだ。フォント指定だとfontタグを使ってしまうから、W3C原理主義者でないボクもちょっと…と思う。まあ、CSSとの整合性を考えると搭載のしようがなかったのだろう。

そこで、
「<span style="font-size: 120%;">大きい</span>」
的なHTMLをあらかじめ定型文として入れておいて、好きなときに呼び出せる─というふうにすれば、代用にできるんじゃないかと思うわけだが。Live Writerにそんな定型文登録・挿入の機能はない。

MSのプラグインコーナーで、海外のものを探してみたらあった。

Text Template
http://gallery.live.com/liveItemDetail.aspx?li=9c8097b3-05f5-4e50-a968-dec6da6aea72&bt=9&pl=8

ちょっとこなれていないが、それなりに使えそうだ。

自分でも使ってみようかな。Live Writer。

2007/08/21

[技術系]   Amazonインスタントストアの登録商品データをダンプするスクリプト

at 17:17JST
指摘されるまで「できないできない…」と思っていたのだが、Amazonインスタントストアは、いつのまにか
「並べる商品ひとつひとつにコメントを書き込める」
ようになっていたらしい。

これだとAmazonのお好み商品をチョイス・分類して、自分で宣伝文句を考えて記録した簡易データベースになる。で、それをほかのネットサービスから呼び出して使う、と。

とりあえずインスタントストアをスクレイピングしてダンプする(汚い)スクリプト。そんで出力をJSONPにしておけば、静的コンテンツで参照できる、と。

あと、インスタントストアって、カテゴリーを複数階層もてるのね。見た目とか使い勝手とかはどうかと思うところもあるけれど、これだと類似サービスつくっても無意味だな。

#!/usr/bin/perl 

package bar::amazon::instant;

use strict;
use Jcode;
use LWP::UserAgent;

my $BASEURL = 'http://astore.amazon.co.jp';

sub GetCatsAndProds {
my $ID = shift @_;

my @cats = GetListOfCategories( $ID );
return # エラー
if ( $#cats < 0 );
my @result;
foreach my $cat ( @cats ) {
my $node = $cat->{node};
my $refProds = GetRefProdsOfCategory( $ID, $node )
or return # エラー
;
$cat->{prods} = $refProds;
if ( $#$refProds > -1 ) {
push( @result, $cat );
}
}
return # エラー
if ( $#result < 0 );
return @result;
}

sub GetListOfCategories {
my $ID = shift @_;

# トップページを取得する
my $cntToppage = GetEucURL( "$BASEURL/$ID" )
or return # エラー
;

# 全「カテゴリー」のnode ID、タイトルを取得する
my @cats;
my %cats;
while (
$cntToppage =~ m|href="/$ID/.*?node=([0-9]+)"[^>]{0,}>(.*?)</a>|g
# <a href="/$ID/503-6975305-3150324?%5Fencoding=UTF8&node=$node">$title</a>
) {
next if ( exists $cats{ $1 } );
$cats{ $1 } = $2;
push(
@cats,
{
node => $1,
title => $2,
}
);
}
# $cntToppage =~ m|href="/$ID/.*?node=([0-9]+)"|g
# http://astore.amazon.co.jp/$ID?node=$node
# として参照できる

#die if ( $#cats < 0 );
return @cats;
}

sub GetRefProdsOfCategory {
my $ID = shift @_;
my $node = shift @_;

my $urlBaseOfThisCategory = "$BASEURL/$ID?node=$node&page=";
my $pageNum = 1;
my $cntStackedPages;
while ( 1 ) {
my $cnt = GetEucURL( "$urlBaseOfThisCategory$pageNum" )
or return # エラー
;
$cntStackedPages .= $cnt;
$pageNum++;
last if ( $cnt !~ m|href="/$ID/.*?node=$node.{0,}?page=$pageNum">.*?&gt;.*?</a>| );
# 次ページ
# <a href="/$ID/503-6975305-3150324?node=$node&amp;page=$pageNum">次 &gt; &gt;</a>
}

my @prods;
my %prods;
#<td><a href="/hirosiki-22/detail/B000JG2DA0/503-6975305-3150324">アイドルマスター(通常版)</a>
#<br>
#<span class="price">¥ 6,069</span>
#<br>ああああアイドルスマター</td>
while (
$cntStackedPages =~
m|(<td><a href="/$ID/detail/[^"]+">[^<]+</a>.*?<span class="price">.*?</td>)|msg
) {
my ( $asin, $title, $price, $comment ) =
(
$1 =~ m|<a href="/$ID/detail/([^/]+)/[^"]+">([^<]+)</a>.*?<span class="price">([^<]{0,}?)</span>(.{0,}?)</td>|ms
)
;
$comment =~ s|<span [^>]+>.{0,}</span>||g;
$comment =~ s|<[^>]+>||g;
$comment =~ tr/\x0D\x0A//d;

next if ( exists $prods{ $asin } );
$prods{ $asin } = $title;
push(
@prods,
{
asin => $asin,
title => $title,
price => $price,
comment => $comment,
}
);
}

return \@prods;
}

sub GetEucURL {
my $url = shift @_;
return # エラー
if ( URLisnotSane( $url ) );

my $refConf = shift @_;
my $timeout = 6;
my $max_size = 128;
if ( $refConf ) {
if ( $$refConf{timeout} ) {
$timeout = $$refConf{timeout};
}
if ( $$refConf{max_size} ) {
$max_size = $$refConf{max_size};
}
}

my $ua = LWP::UserAgent->new(
agent => 'Mozilla/4.0 (compatible; MSIE 6.0)',
timeout => $timeout,
max_size => $max_size * 1024,
);
my $response;
$response = $ua->get( $url )
or return; # エラー
return # エラー
if ( !$response->is_success );
my $eucContent;
$eucContent = jcode( $response->content )->h2z->euc;
$eucContent =~ s/\x0D\x0A|\x0D|\x0A/\n/g;
return( $eucContent );
}

sub URLisnotSane {
my $url = shift @_;
return 1
if (
( $url !~ m#^http://[^\./]+\.[^\./]# ) #要セカンドレベルドメイン
|| ( length( $url ) > 2048 )
);

my $host =
( $url =~ m#http://([^/]+)/?# )[0];
if ( $host =~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/ ) {
my @c =
( $host =~ /^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/ );
my $dec = $c[0]*(256**3)+$c[1]*(256**2)+$c[2]*(256)+$c[3];
return 1
if (
( ( 167772160 <= $dec ) && ( $dec <= 184549375 ) )
|| ( ( 2886729728 <= $dec ) && ( $dec <= 2887778303 ) )
|| ( ( 3232235520 <= $dec ) && ( $dec <= 3232301055 ) )
);
}
#Class A 10.0.0.0〜10.255.255.255 167772160〜184549375
#Class B 172.16.0.0〜172.31.255.255 2886729728〜2887778303
#Class C 192.168.0.0〜192.168.255.255 3232235520〜3232301055

return; # エラー
}

sub HTMLEscape {
my $i = shift @_;
$i =~ s/&/&amp;/g;
$i =~ s/</&lt;/g;
$i =~ s/>/&gt;/g;
$i =~ s/"/&quot;/g;
return $i;
}

sub UnHTMLEscape {
my $i = shift @_;
$i =~ s/\&lt;/</g;
$i =~ s/\&gt;/>/g;
$i =~ s/\&quot;/"/g;
$i =~ s/\&amp;/\&/g;
return $i;
}

1;

package main;
use strict;

use Data::Dumper;

$| = 1;

my $ID =
shift @ARGV
|| 'hirosiki-22'
;

my @result = bar::amazon::instant::GetCatsAndProds( $ID );
print Dumper( @result );


[技術系]   複数枚のプリント写真をいちどにスキャンする

at 11:46JST
現像しちゃった古い写真をパソコンに取り込みたい、ってニーズがあるわけですよ。でも、こういうのはだいたい枚数が多いのでスキャナで一枚一枚取り込むのはめんどう。

たとえば、
200708210100016.png
こんなふうに(勝手に某人の写真を使ってます。ごめん)、3,4枚の写真をまとめてスキャンして、パソコンが赤枠のように一枚一枚の写真を自動認識、
・分割
・微妙な傾きの補正
をして画像ファイルにしてくれたら便利。

こういうのは最近のスキャナでは附属ソフトの機能として搭載されていて、
エプソン→マルチフォトスキャン
キヤノン→ワンパスマルチスキャン
などと言っている。しかし、それぞれのメーカーの対応スキャナを買わなければ、もちろん使えない。

単独のソフトでこういう機能を実現してくれるものもあるはずだろ…と探したら、無料のソフトでは存在しないようだ。ふーむ。

代わりに、Adobe様のPhotoshop(CS2) / Photoshop Elementsにはこの機能があることがわかった。常識? だって、ぼくのPhotoshopはバージョン4だもんで知らなかったのよ。

Elementsで分割したいスキャン画像を読み込んだら、
2007082102mage2.png

メニューの
「イメージ」→「スキャンした画像を分割」
とすると、プリント領域を自動認識して
・切り抜き
・回転
をしてくれる。

結果は以下のように…。
2007082103mage4.png

なんか精度があまり高くなくて(悪く言えばバカ)、二枚づつに切られてしまった。
・写真同士がきちんと離れていないと認識に失敗する
・四角いくっきりした領域がある構図だと、写真の中を切り取られてしまう
といった感じか。

さらに、勝手に回転してくれてしまうし、適当なところで切って矩形にしてくれてしまうため、
・どことなく縦横比率が狂うような気がする
・上下左右が寸詰まりになる
といった問題も。あまり実用的じゃない。

ちなみにPhotoshopでは以下のようにメニューを呼び出すが、認識エンジンが同じもののようで結果はまったく同じになった。
2007082104mage1.png


とりあえず「矩形に切り出す」だけの手軽なツールがあればよいのだが、なぜか見あたらない。領域認識って、画像処理ではわりと歴史の長い分野だと思うのに底辺まで落ちてきてないのだなあ。

Intelの画像処理ライブラリ「OpenCV」を使ってうまくできないかと思ったが、Perl用のバインディングがないのであきらめた。Windows上でライブラリ使うのもめんどくさそうだし。Rubyのほうでは環境がきちんとそろってるのかな?

2007/08/03

[技術系]   だからこれじゃダメなんだってば!>天地中央

at 02:06JST
ボックスを上下左右画面中央に | CSS HappyLife
http://css-happylife.com/log/css-template/000166.shtml

…なんかまた二番煎じのエントリがはてブにあがってる。このやり方で天地中央にしちゃダメなんだってば。

これじゃダメじゃん>天地中央 : ひろ式めもちょう
http://memo.hirosiki.jp/article/48978220.html
スクリーンショットを見てもわかるように、上辺・左辺に向かって消えてしまった領域はスクロールバーの操作で呼び出すこともできないので、万一VGA環境なんかで見たら死ぬほど悲惨なことになる


なんでちゃんと確認しないんだろう。「ウェブヒョージュン」がどーたらとか言う前に、利用者がきちんと違和感なく読めることが最も重要なのは論を待たないと思うのだが。HTML Lintで得点稼ぎごっことかしてる人は、だいたいそういう視点をもたないんだよな。視野が狭い。あえて言っておく。

8/23
また同じようなことを書いている人を見かけた。参考のためにトラックバック。
ボックスをウインドウの中央に表示 (ウェブのあれこれ格納庫)
http://web.hirot.jp/archives/000197.php

2007/07/27

[技術系]   RSSリーダーを簡単にHTMLアプリケーションでつくる32の方法

at 05:54JST
タイトルはバカっぽい感じにしてみただけです。

Google AJAX Feed APIを使ってシンプルなガジェット型RSSリーダーを作成する方法(Windows only) - F.Ko-Jiの「一秒後は未来」
http://blog.fkoji.com/2007/07262155.html

↑を読んで思ったんだけど…壁紙にすることはできないが、ガジェット的なRSSリーダーをWindowsで作るなら、拡張子を.htaにしたHTMLファイルでいにしえの「HTMLアプリケーション」を作成したほうがいい気がする。Googleなんぞの世話にならずとも済む。

↓は1年くらいまえに適当につくったもの。御用新聞サイトの「イザ!」がチームラボかどっかにわざわざカネ払ってRSSリーダーを開発させて配り始めたので、「こんなのカネ払う意味も配る意味もないじゃんよ」と対抗意識燃やしてデッチあげたやつ。ヘンなところでmarquee使ってるうえに未完成だが。やりたいことはわかると思われ。

きちんとしたアプリケーションっぽくシングルインスタンスなうえ、タスクバーにも現れません。

20070727mage1.png


いまの時代を予見するような技術を10年前に実装するとは。さすがゲイツさま! 一生ついていきます。再発見されたJavaScriptのように、ここからHTAのブームが起きることをキボンヌ。なに!? Vistaでは動かない!?(未確認)

ま、F.Koji氏流に言うなら「一秒後は未来」ならぬ
「十年前は未来」
って感じか。

ソースは以下:
<html> 
<head>
<meta
http-equiv="Content-Type"
content="text/html; charset=Shift_JIS"
>
<hta:application
applicationname="jpHirosikiRssbar"
contextmenu="no"
innerborder="no"
maximizebutton="no"
minimizebutton="no"
selection="no"
showintaskbar="no"
singleinstance="yes"
/>
<title>ひろ式RSS</title>
<script
language="JavaScript"
>
var URL = 'http://memo.hirosiki.jp/index.rdf';

var d = document;
var q = "'";

function LoadRSS () {
var oRSS = new ActiveXObject( 'Microsoft.XMLDOM' );
oRSS.async = false;
if ( oRSS.load( URL ) ) {
items = TagContents( oRSS, 'item' );
var listHtml = '';
for ( var i=0; i<items.length; i++ ) {
listHtml +=
'<li>' +
EntryDiv(
'<a href="' +
TagContentText( items[i], 'link' ) +
'">' +
TagContentText( items[i], 'title' ) +
'</a>'
)
;
}
d.getElementById( 'Feed' ).innerHTML =
'<ul>' +
listHtml +
'</ul>'
;
}
}

function EntryDiv ( str ) {
return(
'\
<div\
onmouseover="\
this.parentNode.innerHTML = EntryMarquee( this.innerHTML );\
"\
>%%</div>\
'.replace( /%%/, str )
);
}
function EntryMarquee ( str ) {
return(
'\
<marquee\
onmouseout="\
this.parentNode.innerHTML = EntryDiv( this.innerHTML );\
"\
behavior="scroll"\
scrolldelay="120"\
>%%</marquee>\
'.replace( /%%/, str )
);
}

function TagContents ( elem, tagName ) {
return(
elem.getElementsByTagName( tagName )
);
}
function TagContent ( elem, tagName ) {
return(
TagContents( elem, tagName )[0]
);
}
function TagContentText( elem, tagName ) {
return(
TagContent( elem, tagName ).text
);
}

window.onload = function () {
window.resizeTo( 200, 240 );
LoadRSS();
}
</script>
<style>
* {
font-size: 12px;
font-style: normal;
margin: 0;
padding: 0;
}
h1 {
}
li {
margin-left: 1.5em;
padding-left: 0;
width: 10em;
height: 1em;
overflow-y: hidden;
}
address {
text-align: right;
}
</style>
</head>
<body>
<h1>ひろ式RSS</h1>
<div
id="Feed"
>
</div>
<hr>
<address>
<a
href="http://memo.hirosiki.jp/"
>ひろ式めも</a>
</address>
</body>
</html>


ダウンロード:
rssreader.hta

[技術系]   そんなにSMTP AUTHが優れているとも思えないのだが…

at 02:14JST
DION、メール送信時の「POP before SMTP」を廃止し「SMTP AUTH」に一本化
http://internet.watch.impress.co.jp/cda/news/2007/07/26/16466.html
現在ではSMTPでユーザー認証を行なうSMTP AUTH方式が標準化されており、多くのメールソフトもSMTP AUTHに対応している。
  :
よりセキュリティ面で安全性の高いSMTP AUTH方式に一本化することで、迷惑メール発信などの不正利用の防止対策を強化するとしている


えらい乱暴な話だと思う。なにもPOP before SMTPを今すぐ廃止する理由ってないんじゃないか? 併用しておけばいい。

「技術原理主義者」がこういうことを言うのならわかる。一般ユーザーが触れるプロバイダがこういう主張をして、おまけにINTERNET Watchがそれを鵜呑みにして垂れ流すのってどうよ? Watchにはそれほどの力量がないことは重々承知だが、それでも存在しうるデメリットをかみ砕いて伝えるのがメディアの役目だと思うのだけどね。どうかね。

いろいろツッコミどころがある。たとえば「SMTP AUTH方式が標準化されており」って、いつどこで「標準化」されたんだよ。RFC 2554としてRequest for Commentsな文書が提示されていることを、いつからインターネットは無邪気に「標準化」されたと呼ぶようになったんだ? あくまで実装リファレンスに過ぎない。

まあ、メンテされている多くのMUAがSMTP AUTH対応になっているのは否定しない。でも、インターネット業界は
「いったん世に出てしまった製品は“なかったことにできない”」
ことを忘れやすすぎる。SMTP AUTHなんぞぜんぜん知らないインターネットメール対応製品は、そこらじゅうに転がってる。そういうものが使えなくなってしまうというデメリットを、もう少し強調してもいいはずだ。

…だいたいMTAだと素でAUTHに対応してない某実装とかあるわけですが。まあMTAの話はいいや。

さらに「よりセキュリティ面で安全性の高いSMTP AUTH方式」ってなんだ? どういう観点から見て「セキュリティ面で安全性が高い」というのだ。別にSMTP AUTHにセキュリティ面でのアドバンテージなんてないだろ。AUTH PLAINだったら完全にゼロ。寝言は寝てから言え。クーソーしてから寝てください。

それとSMTP AUTHとスパム送信の踏み台になる云々は、独立した事象な。非SMTP AUTHでも、今どきThird party relayを受け付けてるサーバなんてないだろ。

…と、ちょっと怒ってみたが、まあ廃止は今年度末か。周知期間としては半年設けてるのでそれなりに良心的なのかもしれん。…いや、やっぱちょっと納得行かない。

やっぱオレは古い人間なのだろうか。

2007/07/23

[技術系]   これじゃダメじゃん>天地中央

at 15:50JST
別に「Webヒョウジュン」のようなバカの好きなことばとは関係なく、これってうまく使えないことが多い気がする。

CSSでDivを天地左右中央に配置する方法『locate div at the center vertically and horizontally』 | CREAMU
http://blog.creamu.com/mt/2007/07/cssdivlocate_div_at_the_center.html

ミニマルモデルで示すと、
<html> 
<body>
<div
style="
position: absolute;
top: 50%;
left: 50%;
margin-left: -200px;
margin-top: -100px;
width: 400px;
height: 200px;

border: 1px solid black;
"
>
aaaa
</div>
</body>
</html>


こういうことなんだけど、これって
「ウインドウサイズが天地左右中央にしたいボックスより小さいと、
 そのボックスの上辺・左辺が消えてしまう」
よね。

具体的に
http://blog.creamu.com/
で示すと(XP+IE7使用。Firefox系も同じ)、ウインドウサイズが十分に大きい場合は
20070723cssmage1.png

となって期待通りだが、小さくしてみると
20070723cssmage2.png

といったように上辺・左辺が欠ける。というか四辺全部が欠けるということなんだけどね。

欠けるのが下辺・右辺だけならいいのだが、上辺・右辺が欠けると
・違和感がある
・ナビゲーションバーなど上辺・右辺に配することが多いパーツが消える
という問題点がある。特に後者が致命的。

「こまけーこといってんじゃねーよ。
 こんなウインドウサイズにして見るヤツいねーよぼけー」
とか言う? いや、そうじゃなくて…天地左右中央にボックスを配置したいのって、
「描画領域をXGA(1024×768ドット)決め打ちで作っているサイトを
 SXGA・WXGAディスプレイで見たとき、
 描画領域を中央にもってくることでつじつまを合わせたい」
場合が多いじゃない? そういうケースで描画領域がスクロールバーなどの分量を計算に入れていないとき、XGAディスプレイでフルスクリーン表示しても上辺・左辺が欠けてしまうんだよね。

おまけに、スクリーンショットを見てもわかるように、上辺・左辺に向かって消えてしまった領域はスクロールバーの操作で呼び出すこともできないので、万一VGA環境なんかで見たら死ぬほど悲惨なことになる。

ということなので、この手法は使う場所を考えないといけないと思う。

めんどくさいねー。もっと簡単に天地中央にしたいよねー。…はっ! いま、誰もが納得するうえにインターオペラビリティ豊かな解決策を思いついたよ!! それはtabl(以下Web標準原理主義者による検閲で削除)

[技術系]   update pingを受け取って何かを起動するCGIスクリプト

at 11:13JST
というのを適当にでっちあげている。

たとえばいま、このblogはn分おきにcronで更新チェックしてmixiに転載されたりしているが、これは非常にムダである。update pingを受け取ったときに更新チェックしに行くスクリプトを起動するようにしておけば省エネだ。これをタスクaとする。

もうひとつ。update pingを受け取ったらRSSを取得しにゆき、特定カテゴリの記事だけを蓄積してDB/RSS化するスクリプトもあれば便利だ。これをタスクbとする。

というわけで。しかし、

Weblogs.Com changes.xml を吐いたりする Ping サーバの Perl 実装 : NDO::Weblog
http://naoya.dyndns.org/~naoya/mt/archives/000444.html

あたりの事例のようにXMLRPCに沿ってマジメに書くのはいかにもメンドくさい。だって、weblogUpdates.pingのベーシックな中身って、
<?xml version="1.0"?> 
<methodCall>
<methodName>weblogUpdates.ping</methodName>
<params>
<param><value>testblog-blog</value></param>
<param><value>http://memo.hirosiki.jp/</value></param>
</params>
</methodCall>

こんだけなのだ。ムダきわまりない。そもそもXMLRPCキライだしね。

なので単純にPOSTで受け取って正規表現で更新サイトのURLを取得するだけにした。そのほか、もーほんとに適当に書き殴ってみる。

それでスクリプトの末尾に設定を
memo.hirosiki.jp	mailto	hoge@hoge.jp 
memo.hirosiki.jp !/var/net/www/hirosiki.jp/update.ping/something.to.exec

のように羅列しておくと、順に読んで処理してくれる。mailtoは更新通知メール送信コマンド。!のあとにパスを添えると外部コマンド起動。これでタスクaは完了。

で、タスクbのほう。とりあえず、
・更新通知を受ける
  ↓
・更新されたサイトからRSS auto discoveryでRSS URL取得
  ↓
・RSS取得
をやる。RSS auto discoveryももちろん正規表現で。この程度のことでTokeParserなんて使ってられるか。

…しかし、
・RSSを解析してローカルDBにストア
・特定カテゴリだけのRSSをストア
という処理で困った。
・RSS 1.0とRSS 2.0で大幅に仕様が違うので差異の吸収がめんどう
・パースがけっこうめんどう
うーん。しかし、ここでXML::RSSを使いたくないな…。そもそもXMLがキライだからな…。wellformedでないXMLを読むとショックで死ぬようなモジュール使えるか、ボケ。どうしようか。

以下、汚いスクリプト。
#!/usr/bin/perl 

use strict vars;
use Jcode;
use LWP::UserAgent;

my $req;
if ( $ENV{'REQUEST_METHOD'} eq 'POST' ) {
read( STDIN, $req, $ENV{'CONTENT_LENGTH'} );
} else {
FatalResponse( 503 );
}
=rem
* Seesaaでの例
<?xml version="1.0"?>
<methodCall>
<methodName>weblogUpdates.ping</methodName>
<params>
<param><value><string>testblog-blog</string></value></param>
<param><value><string>http://memo.hirosiki.jp/</string></value></param>
</params>
</methodCall>

* MovableTypeでの例
<?xml version="1.0"?>
<methodCall>
<methodName>weblogUpdates.ping</methodName>
<params>
<param><value>testblog-blog</value></param>
<param><value>http://memo.hirosiki.jp/</value></param>
</params>
</methodCall>
=cut

my $url =
( $req =~ m!<value>(?:<string>)?(http://.*?)(?:</string>)?</value>! )[0]
;

Response();

while ( <DATA> ) {
s/^\s+//;
s/\s+$//;
next if ( /^$/ || /^#/ );
my $name = ( split( /\t/, $_ ) )[0];
my $rest = $_;
$rest =~ s/^$name\t//;
my @args = split( /\t/, $rest );
my $cmd = shift @args;

next
if ( $url !~ m|^http://$name| );

if ( $cmd =~ s/^!// ) {
system( $cmd );
next;
}

my $cmdroutine = "__cmd_$cmd";
&$cmdroutine( $url, @args );
}

exit;

sub __cmd_mailto {
my @args = @_;
my $site = shift @args;

system( "echo '$site' | mail -s '[ping received] $site' $args[0]" );
}

sub __cmd_rssaddto {
my @args = @_;
my $site = shift @args;

my $cnt = GetRSS( $site )
or do {
Warn( "Could not get $site content" );
exit;
};
print STDERR substr( $cnt, 0, 20 ) . "\n";
}

sub GetRSS {
my $site = shift @_;

my $rssUrl = GetRSSURL( $site )
or return; # エラー
my $cnt = GetEucURL( $rssUrl )
or return; # エラー

return( $cnt );
}

sub GetRSSURL {
my $site = shift @_;

my $cnt = GetEucURL( $site )
or return; # エラー
my $rssUrl =
( $cnt =~ m|<link(?:.*)?type="application/rss\+xml"(?:.*)?href="(.*)"[^>]{0,}>|ig )[0]
;
return # エラー
if ( $rssUrl !~ /^http:/ );

return( $rssUrl );
}

sub Warn {
print STDERR shift @_;
}

sub GetEucURL {
my $url = shift @_;

my $refConf = shift @_;
my $timeout = 10;
my $max_size = 128;
if ( $refConf ) {
if ( $$refConf{timeout} ) {
$timeout = $$refConf{timeout};
}
if ( $$refConf{max_size} ) {
$max_size = $$refConf{max_size};
}
}

my $ua = LWP::UserAgent->new(
agent => 'Mozilla/4.0 (compatible; MSIE 6.0)',
timeout => $timeout,
max_size => $max_size * 1024,
);
my $response;
$response = $ua->get( $url )
or return; # エラー
return # エラー
if ( !$response->is_success );
my $eucContent;
$eucContent = jcode( $response->content )->h2z->euc;
return( $eucContent );
}

sub FatalResponse {
my $r = shift @_;
print "Response: $r\n\n";
exit;
}

sub Response {
my %params = (
flerror => 0,
message => 'Thanks for the ping',
@_,
);

print <<"_EOF_";
Content-Type: text/xml

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<struct>
<member>
<name>flerror</name>
<value>
<boolean>$params{'flerror'}</boolean>
</value>
</member>
<member>
<name>message</name>
<value>$params{'message'}</value>
</member>
</struct>
</value>
</param>
</params>
</methodResponse>
_EOF_
}

__DATA__
#memo.hirosiki.jp mailto hoge@hoge.jp
#memo.hirosiki.jp !/var/net/www/hirosiki.jp/update.ping/something.to.exec


そーす:update-ping.cgi

2007/07/13

[技術系]   TweakUIで消えないのだろうか

at 19:05JST
デスクトップ百景
第二十八景:
縦タスクバーとFaviconの活用で「究極の画面効率」を目指すデスクトップ
秋田真宏(あきやん)
http://bb.watch.impress.co.jp/cda/desktop/18793.html
そしてどうしても消し方がわからなかったMy Bluetooth Placesです。(どなたか消し方を知っていたら教えてください……。)


ふーむ。
デスクトップに出る特殊フォルダは、TweakUIから消せると思うが(つまりレジストリをいじる)。ダメだったのだろうか。
20070713001mage1.png

というか、こんなアイコンを増やすなんてどこのBluetoothスタックだ。ぼくならこんなの買ったら捨てる。…って言っても、どこのBluetoothアダプタもひどいのが多いからなあ。どんぐりの背比べか。普及しない原因がこんなところにも。

[技術系]   jugemで「このエントリを編集する」リンクをつける

at 01:34JST
あまりデザインにこだわっていなければ、このblogのようにタイトルの脇などに
「この記事を編集する画面にジャンプする」
リンクをつけておくと(うちではえんぴつの画像になっている)、あとで誤字・脱字を見つけたときクリックするだけで編集画面に入って直せる。べんり。

で、世界一のヘンタイblog(でもないか?)であるところのseesaa BLOGでは、そういうカスタマイズはもちろん容易だ。しかし、最近現実逃避がてらカスタマイズしている
「jugem系のblog」
は、とにかくカスタマイズしづらい。こういうことが簡単にはできない。
※jugem系=おなじ会社のロリポブログなど含む

http://blogサイト名/admin/?mode=entry&eid=該当エントリID

というリンクを作ればいいだけなのだけれど、エントリIDを取得する方法がないのだ。
http://jugem.jp/manual/manual.php?mode=r01
を見ると{eid}が使えそうに見えるけれど、これは
BEGIN entry
  :
END entry
ブロックの中では無効だ。

しかたないのでJavaScriptを使うことにした。
<script 
language="JavaScript"
><!--
var url = '{entry_permalink}';
url = url.replace( '/?', '/admin/?mode=entry&' );
var txtTemplate = '\
<div\
align="right"\
>\
<a\
href="%URL%"\
title="編集"\
><img\
src="/images/enpitu_p_10_10.gif"\
width="10"\
height="10"\
border="0"\
></a>\
</div>\
';
txtTemplate = txtTemplate.replace( /%URL%/, url );
document.write( txtTemplate );
// -->
</script>

これで、
20070713mage1.png

こんなふうに。

現実逃避にちょうどいい小ネタだ。

しかし、この程度のこともできないjugemの低カスタマイズ性というのはどうにかならんのか。

2007/07/12

[技術系]   QuickTimeのフルスクリーン再生って質が悪くて…

at 14:34JST
窓の杜 - 【NEWS】Apple、フリー版でもフルスクリーン再生に対応した「QuickTime」v7.2を公開
http://www.forest.impress.co.jp/article/2007/07/12/quicktime72.html

もともとフルスクリーン再生に対応しているPro版をもっているが、はっきり言って使えたものじゃない。ネットワーク共有上のファイルを直接開いた場合など、コマ落ちならともかく音声再生が落ちるのだ。画質もよくないし、全体的に動作が重い。こんなの無料版で提供して当然。というかちゃんと実装見直せ。

ちなみに同じようなことを
・Windows Media Player
のほかフリーソフトの
・MPlayer Classic
・VLC
でやっても、難なくこなす。

QuickTime Playerは名前の長いファイルも開けないし。

はっきり言ってAppleのソフトウェア技術にはなんの期待もしていない…。

2007/06/27

[技術系]   ここらへんが順当か

at 04:46JST
http://memo.hirosiki.jp/article/45957008.html
つづき。

カンで。
Timeout                 120 
KeepAlive Off
MaxKeepAliveRequests 1
KeepAliveTimeout 5
MinSpareServers 5
StartServers 5
MaxSpareServers 15
MaxClients 50
MaxRequestsPerChild 100



2007/06/26

[技術系]   こんなもんかな

at 15:36JST
KeepAliveをOffにしてみた
http://memo.hirosiki.jp/article/45937396.html

20070626001mage1.png


ふむ。お恥ずかしい。

[技術系]   KeepAliveをOffにしてみた

at 10:34JST
やられた。

またサーバが過負荷になって業者に落とされた。…いや、安いVPSなのに酷使しているぼくが悪いんです。業者は悪くありません。時間にして30分程度だし、出かける前でよかった。

原因はわかってて、mod_perl/masonで「カンレン.えんとり〜ず」を動かしているのが(たいしたことないレベルの)利用増で負荷になっているのだ。

で、ここまで
「スクリプトを書き直そう」
という対処方針だったのだが、よく考えたらmod_perl使ってるにもかかわらずApacheの設定をいじってなかった。

KeepAlive              On 
MaxClients 150

早い話デフォルトなのだ。…そりゃ落ちるよな。

とりあえず
KeepAlive               Off 
MaxClients 90

にしてみた。ベンチマーク採ってる余裕もないので。うちは細々画像ファイルのあるようなサイトは運営していないので、KeepAliveは要らない。

半日、これでようす見る。

あと、bindのTTLが短すぎる…。

2007/06/25

[技術系]   秀丸メールの「@の偽装処理」

at 13:23JST
元「鶴亀メール」こと「秀丸メール」に、
「マルウェア対策で、
 保存メールファイルやレジストリ中のメールアドレスに使われる
 “@”を偽装する」
機能がついた(まだβ)。

http://hide.maruo.co.jp/software/tk.html

これはけっこういいアイデアだよね。ほかのMUAでの対応は聞かないけれど、メール拡散型のウイルスはHDD中のファイルからメールアドレスを抽出するので対策としては効果的だ。

まるお氏の報告メールなどを読んでいて進捗は知っていたのだが、これまで手を出してなかった。バージョンアップついでに試してみることにした。

全般オプションから「@の偽装をする」設定にすると、まず既存のデータの@をすべて偽装する処理に入る。これ、メールボックスが巨大な人はものすごい時間がかかるので注意。ぼくは3時間経つがまだ終わりません…。

で、実際にどのように偽装しているのか見てみた。

…ファイル中の「@」を「0x7F」(DEL)に置き換えてるだけだ。

苦笑。
まるおさんらしいやり方だ。

まあ、そこらへんのいけすかない技術者なら
「確実性を期すため、メール全文を転置式で暗号化する」
とか
「インターネット標準に基づき、URLエンコードする」
とか言い出しそうだし、ぼくだって
「メール本文中にDELが入ってる可能性だってゼロじゃないだろ!」
(↑秀丸では、その場合エスケープするもよう)
とか気にかかるんだけど。

しかし、シェアの低い秀丸メールで、実装・動作速度などを多角的に考えると─というか直観的に“考える”と、DELで置換するのがいちばんコスト対効果がよいのは間違いない。

ほかのMUAが足並みをそろえてURLエンコードする実装を取り入れたりしたら、マルウェアはそれに対応するだけでおいしい思いをするわけだ。しかしこんな“アホな”実装をするのは秀丸だけなので唯一助かりそうな気がする。

とりあえずしばらく使っていて、問題がなさそうだったら他の人のところの秀丸メールも偽装バージョンに入れ替えさせよう。

注:LAN上で複数のクライアントからメールボックスを共有するかたちで秀丸メールを使っている人が偽装処理を利用する場合は、すべてのクライアントをバージョンアップする必要がある

[技術系]   display:none;でもformデータは送信されるんだよな…

at 08:04JST
なんか気になったので念のためやってみた。

#!/usr/bin/perl 

use strict;
use CGI;

print "Content-Type: text/html\n\n<pre>List:\n";

my $q = CGI->new();
my @params = $q->param();
foreach my $param ( @params ) {
print $param, "\t", $q->param($param), "\n";
}

print "</pre>\n";


というスクリプトに対して、

<form 
method="post"
action="test.cgi"
>
<dl>
<dt>t1</dt>
<dd
style="
background-color: #aaa;
"
>
<input
type="text"
name="t1"
value="t1"
>
</dd>
<dt>t2</dt>
<dd
style="
display: none;
background-color: #ccc;
"
>
<input
type="text"
name="t2"
value="t2"
>
</dd>
<dt>t3</dt>
<dd
style="
background-color: #eee;
"
>
<input
type="text"
name="t3"
value="t3"
>
</dd>
</dl>
<input
type="submit"
>
</form>


というフォームからsubmitした場合。ここではname="t2"のtextフィールドがdisplay: none;になっている。

IE7/Firefox 2/Opera 9いずれも
List: 
t1 t1
t2 t2
t3 t3

となる。

当たり前…なんだけど(理屈から言えばこうでないと困るわけで)。どこかでそうじゃない事例を見たんだよなあ…どこだったんだろう。気になる。JavaScriptでDOM操作しているときに限った話だったろうか。

2007/06/23

[技術系]   だから栗はキライだって言ってるじゃん!

at 04:27JST
インテル、どら焼きでおばあちゃんにCore 2 Duoをアピール:ニュース - CNET Japan
http://japan.cnet.com/news/tech/story/0,2000056025,20351401,00.htm

インテルのCPUプロセッサプロモーションキャンペーンを巣鴨で開催、7月末の毎日先着200名に特製どら焼きを配るという話。

実効性のない奇抜なプロモーションなので中身はどうでもいいのだが、ここで配る「どら焼き」の中身には納得いかない。

コアが2つのCore 2 Duoにかけて栗が2つ入ってる!
http://japan.cnet.com/news/tech/story/0,2000056025,20351401-2,00.htm
くわっ!
粒あんだけでも許せないのに、栗なんか入れるな! おれはモンブランのてっぺんの栗も除去してからおいしくいただくくらい、筋金入りの栗ギライなんだよ! あんな邪悪なものを食物としてバラ撒くことは死んでも許さん!


去年からトンチキなことやってるんだよな、インテル…。カネ余りと見た。

インテルのCore 2 Duoがクリスマスツリーに--アキバにCPU2000個を使ったツリー登場:ニュース - CNET Japan
http://japan.cnet.com/news/tech/story/0,2000056025,20310007,00.htm

2007/06/21

[技術系]   Vistaもいいけど…

at 09:13JST
マイクロソフト、Windows Vista SP1のベータ版を年内にリリースへ
http://japan.cnet.com/news/biz/story/0,2000056020,20351240,00.htm

頼むからIE 7のSP1を先に出してくれ…。
IE4のころのβやマイナーバージョンリリースの嵐が懐かしい。
さらに過去の記事
2009/04 (1)   2008/12 (3)   2008/11 (9)   2008/10 (10)   2008/09 (20)   2008/08 (2)   2008/07 (23)   2008/06 (16)   2008/05 (22)   2008/04 (11)   2008/03 (21)   2008/02 (20)   2008/01 (21)   2007/12 (32)   2007/11 (37)   2007/10 (46)   2007/09 (63)   2007/08 (33)   2007/07 (41)   2007/06 (81)   2007/05 (173)   2007/04 (168)   2007/03 (113)   2007/02 (123)   2007/01 (92)   2006/12 (111)   2006/11 (185)   2006/10 (20)  

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は1年以上新しい記事の投稿がないブログに表示されております。