本を読む

読書やコンピュータなどに関するメモ

Fedora 8 test 2でディレクトリ名が日本語になる

 Fedora 8というLinuxディストリビューションの事前テスト版test 2をインストールしてみた。

 いちばん驚いたのが、ホームディレクトリの下に「デスクトップ」や「ダウンロード」といった日本語名のディレクトリができていたこと。Fedora 7では「Desktop」「Download」といった英語表記だったのだけど。

Fedora 8 test 2 userdirs

 たとえばALT+PrtScで画面キャプチャーを撮ったとき、デフォルトは~/Desktopになるような気がするが、該当するディレクトリがないので~になるのだと思う。

どうして変わったか

 以下、どこが変わってこうなったかを手短に。

 これらのディレクトリは、xdg-user-dirsという仕組みで、ログイン時に作られている。

 設定ファイルを見てみると、/etc/xdg/user-dirs.defaultsと/etc/xdg/user-dirs.confは、Fedora 7と同じようだ。

 続いてメッセージカタログを確認。/usr/share/locale/ja/LC_MESSAGES/xdg-user-dirs-gtk.moを、「デスクトップ」とか「ダウンロード」とかでgrepしてみる。Fedora 7ではマッチしないが、Fedora 8 test 2ではマッチする。

 そこでxdg-user-dirsのソースから.poファイルを調べてみる。Fedora 8 test 2のリポジトリからxdg-user-dirs-0.9-1.fc8.src.rpmをダウンロードし、展開すると、po/ja.poファイルで定義されている。

 いっぽう、Fedora 7のリポジトリからxdg-user-dirs-0.8-1.fc7.src.rpmをダウンロードし、展開すると、po/ja.poファイルは存在しない。

 つまり、いままで日本語化設定がなかったものが、ここで追加されたことによるようだ。

「墨攻」

 中国の戦国時代を舞台に、流浪の軍事コンサルタント(墨家)が、小国を大国の攻撃から守ろうとする物語。漫画や映画になって、気になっていたのだけど、ようやく読んだ。

 これは面白い。中国の歴史物語の1エピソード風に、シミュレーションウォーゲームを語る試みというか。主人公を、血も涙もない、でも職人かたぎのテクノクラートにしたところも、味を出している。

 漫画や映画では、また違う話にしているようで、そっちも見てみるか。

墨攻 (新潮文庫)
墨攻 (新潮文庫)
posted with amazlet on 07.09.25
酒見 賢一
新潮社 (1994/06)
売り上げランキング: 9445

「俺と悪魔のブルーズ」4巻

 ロバート・ジョンソンをモデルにしたRJと、「ボニーとクライド」のクライド・バローというハミ出し者2人が南部を旅するマンガ。

 この巻も、ここのところ続いている、禁酒とリンチの町からの脱出の話。普通の主婦など、町の善男善女がリンチや山狩りに参加するあたりがこのマンガらしい。最後でジューク・ジョイント(黒人酒場)にたどりついて、久しぶりにブルーズねたになりそうだ。

 巻末解説は仲井戸麗一(チャボ)。本体価格が666円で、オビに小さく「悪魔的価格」書かれているのがオチャメ。

俺と悪魔のブルーズ 4 (4) (アフタヌーンKC)
平本 アキラ
講談社 (2007/09/21)

「仮面ライダーSpirits」13巻

 V3が…ライダーマンが…滝が…

 後半は、JUDOが住む異空間でZXが戦う! しかも相手は…

仮面ライダーSPIRITS 13 (13) (マガジンZコミックス)
石ノ森 章太郎 村枝 賢一
講談社 (2007/09/21)

「Q.E.D.」28巻/「C.M.B.」6巻

 同じ著者が描いたミステリー2作品の主人公たちが共演する企画。といっても、謎と解決はそれぞれ別もので(よくも悪くも)、どちらから読んでもネタバレになることはないのでご安心を。

 とりあえず「Q.E.D.」から先に読んだ。

 共演企画「ファラオの首飾り」と、単独作「人間花火」を収録。「ファラオの首飾り」は、エジプトの墓の発掘現場での事件と、墓自体の謎をからめた作品。

 が、なにより「人間花火」にはびっくりした。こいつはやられた。そういうズラし方で来たか。



 続いて「C.M.B.」を読んだ。こちらは、共演作「カノポスの壷」1作のみ収録。共演度はこちらが上かな(塔馬君というより水原さんだけど)。殺人事件が軸にあるんだけど、それよりピラミッド自体の謎に対する榊森羅君の説が面白かった。空想上の昔の人や未来の人がユーモラスだし。


「外注される戦争」

 イラクで元自衛官の民間軍事会社(PMC)員が殺害された事件が起きてから、日本でもPMCが知られるようになった。本書は、それらPMCを解説する本。

 大所高所から産軍共同がケシカランとか論じる本ではなくて、PMCのビジネス内容や現場の様子、動向などを、ひとつのビジネスとして、綿密な取材を元に描いている。中でも、ジャーナリスト向けセキュリティ訓練は、死と背中合わせの戦場を疑似体験したレポートで、出色の読みものだ。もっとも、取材や分析が綿密すぎて、著者はPMCのコンサルタントとしてスカウトされてしまったそうだ。巻末には、代表的なPMCの紹介を掲載。

外注される戦争―民間軍事会社の正体
菅原 出
草思社 (2007/03/24)
売り上げランキング: 47762
  • PMCの業務
    • 一口にPMCといっても、会社ごとに分野が違う
    • 後方支援を請け負う会社がほとんど
    • 要人や施設などの警備
    • 軍事訓練
    • 人質解放交渉
    • ロジスティックス
    • 兵器のメンテナンス
    • インテリジェンス活動(戦争広告代理店を含む)
    • 収容所での尋問
    • 地雷処理
    • 現地の文民警察
    • 一部には、前線での戦闘に参加する会社も
  • 米軍の民間委託の流れができてきたのはベトナム戦争から
    • 冷戦集結により、軍の人員削減と紛争増加が起き、民間委託が進んだ
    • 軍からリストラされた軍人がPMCに
  • イラク戦争でPMCバブルに
    • イラクに送った人員は、アメリカ以外の1国よりPMCのほうが多い
    • 米軍はもはや、PMCなしに活動することは不可能とまでいわれている
    • 直接の戦闘だけではなく、テロの脅威への対策が必要
    • イラクの武装勢力にとって、誘拐は有力な「ビジネス」
    • 経験なしに参入する、ぽっと出の会社も多い
      • レベルやモラルの低い会社も
      • 捕虜虐待や、銃の乱射など
      • 利益に走りすぎて派遣人員の安全性が軽視されることも
      • PMCどうしで相互に危険などの情報を交換する業界団体ROCが発足
    • 元警察官
    • 元トラック野郎
    • フィジーやフィリピン、ネパールなどからの出稼ぎ
  • エリート限定採用で差別化する会社も
  • 特殊部隊出身者は引っ張りだこ
  • 元自衛官の所属していた会社はROC非加入
  • もともとは、特殊部隊出身者によるインナーサークル的性格(顔見知り)
    • 民間のほうがより実践的な戦闘技術が学べる、と特殊部隊からの人材流出が続く
  • CIAをPMCが警護するケースや、正規軍をPMCが訓練するケースも
  • 政治的に米軍を派遣しにくい国に、米政府の依頼でPMCを送るケース
  • ロイズのリスク管理のため、警備や人質解放交渉を請け負うPMCを紹介するケース

 読んでいて、民間の軍事インストラクターを主人公にした「パイナップルARMY」や、特殊部隊出身のロイズ調査員を主人公にした「MASTERキートン」といったマンガを連想した。

パイナップルARMY (Operation 1) (小学館文庫)
工藤 かずや 浦沢 直樹
小学館 (1995/11)
売り上げランキング: 18667
MASTERキートン (1) (ビッグコミックスワイド)
勝鹿 北星 浦沢 直樹
小学館 (1998/11)

Re: Web::Scraper 0.13をdh-make-perlしたらエラー

Generated error: Error: syntax error at /home/user/hansode/work/debian/Web-Scraper-0.13/Makefile.PL line 2, near "name 'Web-Scraper'"

 PerlモジュールのDebian用パッケージで、いろいろお世話になってます。

 dh-make-perlが呼んでるModule::Depends::Intrusiveは、Makefile.PLが呼んでる関数をトラップして実行することで、依存関係を調査してます。で、debian標準のlibmodule-depends-perlはバージョン0.10なので(unstableでも)、nameをトラップしてくれないようです。

 そこで、libmodule-depends-perlを、Module::Depends 0.13ベースにアップデートしたら(uupdateを使用)、name関数がエラーにならなくなりました。

 ただし、今度はinstall_script関数がエラーに。

$ dh-make-perl Web-Scraper-0.16
Found: Web-Scraper 0.16 (libweb-scraper-perl arch=all)
======================================================================
Could not find the dependencies for the requested module
Module::Depends::Intrusive reports: syntax error at /home/masaka/tmp/Web-Scraper/Web-Scraper-0.16/Makefile.PL line 18, near "install_script 'bin/scraper'"
Compilation failed in require at /usr/share/perl5/Module/Depends/Intrusive.pm line 83.

Generated error: Error: syntax error at /home/masaka/tmp/Web-Scraper/Web-Scraper-0.16/Makefile.PL line 18, near "install_script 'bin/scraper'"
Compilation failed in require at /usr/share/perl5/Module/Depends/Intrusive.pm line 83.

Please check if your module depends on Module::Install
for its build process - Automatically finding its
dependencies is unsupported, please specify them manually
using the 'depends' option. 
======================================================================

 調べてみると、Module::Depends::Intrusive.pmを書き換えて、ニセのinc::Module::Install::EXPORTにinstall_scriptを追加してやればいいようです。

--- lib/Module/Depends/Intrusive.pm.orig	2007-06-26 21:44:36.000000000 +0900
+++ lib/Module/Depends/Intrusive.pm	2007-09-20 21:29:39.000000000 +0900
@@ -61,7 +61,7 @@ sub _find_modules {
       all_from auto_install AUTOLOAD build_requires check_nmake include
       include_deps installdirs Makefile makemaker_args Meta name no_index
       requires WriteAll clean_files can_cc sign cc_inc_paths cc_files
-      cc_optimize_flags author license
+      cc_optimize_flags author license install_script
 
     );
     local *inc::Module::Install::AUTOLOAD = sub { 1 };

 こういうのって、どこにレポートすればいいんですかね?

 それにしてもdh-make-perlが呼んでるapt-fileは、時間がかかるなぁ。

首相の名字をWebから自動取得してみる

 スパムよけで、トラックバックURLに「日本の首相の名字」を含めさせるブログがある。しかし、首相は変わりうる。そこで、Webから自動取得してみる実験。

 実用性はナシ。むしろ、スパマーを助けてる気もする。

kantei.go.jpから取得

 PerlのWeb::Scraperを使って、kantei.go.jpの英語版から取ってきてみる。

#!/usr/bin/perl
use strict;
use warnings;
use URI;
use Web::Scraper;

my $url = 'http://www.kantei.go.jp/foreign/index-e.html';

my $result = scraper {
    process '//h2/img[@src =~ /title_daijin\.gif\Z/]', 'text' => '@alt';
    result 'text';
}->scrape(URI->new($url));

$result =~ s/\APrime Minister [^ ]+ ([^ ]+) *\Z/$1/;
print lc($result), "\n";

 プロフィール欄から名前を持ってきている。ただ、一般的に、プロフィールの見せ方は変わりがちなのが弱点だ。

cia.govから取得

 デザインの変わりにくい、データベース的なページを探してみた。CIAの「World Leaders」コーナーがそれっぽい。

#!/usr/bin/perl
use strict;
use warnings;
use URI;
use Web::Scraper;

my $url = 'https://www.cia.gov/library/publications/world-leaders-1/world-leaders-j/japan.html';

my $result = scraper {
    process '//tr/td[text() =~ /Prime Min\./]/../td[2]', 'text' => 'TEXT';
    result 'text';
}->scrape(URI->new($url));

$result =~ s/\A[^ ]+\s+([^ ]+)\Z/$1/;
print lc($result), "\n";

 ただし、この政局のためか、試した時点では最新の閣僚名簿になっていないようだ。なので、首相が交代したときに反映されるタイミングは不明。

まとめ

 Web::Scraper便利。HTMLのgrepって感じ。

祝日のリストをGoogle Calendar APIを使って作る

 祝日判定をやりたいときがたまにある。たとえば、指定した日の次の平日はいつ、とか。

 データを自前で抱えるのは面倒なので、Web APIで一覧を取れないかと探してみた。どうやらGoogle Calendar APIでできるらしい。呼ぶ部分をRubyで試作してみる。

require 'set'
require 'date'
require 'open-uri'
require 'rexml/document'

HOLYDAY_URL_PTN = 'http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full?start-min=%s&start-max=%s'

class HolidayList < Set
  def initialize(from, to)
    super()
    from_s = from.strftime('%F')
    to_s = to.strftime('%F')
    open(HOLYDAY_URL_PTN % [from_s, to_s]) {|io|
      doc = REXML::Document.new(io)
      REXML::XPath.match(doc, '//entry/gd:when/@startTime').each {|elm|
        self << Date.parse(elm.to_s)
      }
    }
  end
end

 試す。

irb(main):001:0> require 'holidaylist'
=> true
irb(main):002:0> list = HolidayList.new(Date.new(2007, 9, 1), Date.new(2007, 9, -1))
=> #<HolidayList: {#<Date: 4908721/2,0,2299161>, #<Date: 4908733/2,0,2299161>, #<Date: 4908735/2,0,2299161>}>
irb(main):003:0> list.sort.each {|d| puts d.strftime('%F')}
2007-09-17
2007-09-23
2007-09-24
=> [#<Date: 4908721/2,0,2299161>, #<Date: 4908733/2,0,2299161>, #<Date: 4908735/2,0,2299161>]

 まぁ、APIまんまなんだけど。このあたりを参考にした。

どう書く?org:改行をBRタグに置き換える

 前回のプログラムに2行を追加するだけ。もともとタグ内とテキストを区別してるので。

--- tagescape1.c        2007-09-01 12:21:57.000000000 +0900
+++ tagescape2.c        2007-09-04 21:13:37.000000000 +0900
@@ -199,6 +199,8 @@ static void te_parse_plain(te_status *st
     while ((c = *(status->p_src++)) && (status->size > 0)) {
        if (c == '<') {
            te_parse_tag(status);
+       } else if (c == '\n') {
+            te_puts(status, "<br />");
        } else {
            te_putc(status, c);
        }

どう書く?org:重複する要素を取り除く

 sedで。

s/$/#/
:loop
s/\(.\)\(.*\)\1\(.*\)$/\2\3\1/
t loop
s/#.*//

 実行例。

$ echo '314159265' | sed -f onlyunique.sed 
34926

追記2008-08-19:
なんとなく、どう書く?.orgに投稿してみました

どう書く?org:一部のHTMLタグを通すフィルタ

 LL、HTMLパーサー、正規表現を禁じて、わりと素のCで書いてみる。

 結論。LL、ライブラリ、パーサー、正規表現は偉大だ。

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>

#define MAXDATASIZE     (1024 * 1024)
#define BUFSIZE         1024

typedef struct {
    char *p_src;
    char *p_dest;
    int size;
} te_status;

static void te_putc(te_status *status, char c)
{
    if (status->size > 0) {
        *(status->p_dest++) = c;
        status->size--;
    }
}

static void te_puts(te_status *status, char *str)
{
    char c;

    while (c = *str++) {
        te_putc(status, c);
    }
}

static void te_skip_space(te_status *status)
{
    char c;

    while ((c = *(status->p_src)) && isspace(c)) {
        status->p_src++;
    }
}

static void te_parse_name(te_status *status, char *p, int size)
{
    char c;

    while ((size > 0) && (c = *(status->p_src)) && isalnum(c)) {
        status->p_src++;
        *p++ = c;
        size--;
    }
    *p = '\0';
}

static void te_parse_tagname(te_status *status, char *p, int size)
{
    if ((size > 0) && (*(status->p_src) == '/')) {
        status->p_src++;
        *p++ = '/';
        size--;
    }
    te_parse_name(status, p, size);
}

static void te_parse_quote(te_status *status, char *p, int size)
{
    char c;
    char startchar;
    int backslash_flag = 0;

    startchar = *p++ = *(status->p_src++);
    size--;
    while ((size > 0) && (c = *(status->p_src))) {
        status->p_src++;
        if (((c == '<') || (c == '>')) && (size >= 3)) {
            sprintf(p, "%%%2X", c);
            p += 3;
            size -= 3;
        } else if (size > 0){
            *p++ = c;
            size--;
        }
        if ((! backslash_flag) && (c == startchar)) break;
        backslash_flag = (c == '\\') ? 1 : 0;
    }
    *p = '\0';
}

static void te_parse_elmvalue(te_status *status, char *p, int size)
{
    if ((*(status->p_src) == '\'') || (*(status->p_src) == '\"')) {
        te_parse_quote(status, p, size);
    } else {
        char c;

        while ((size > 0) && (c = *(status->p_src)) &&
               (! isspace(c)) && (c != '>') ) {
            *p++ = c;
            status->p_src++;
            size--;
        }
        *p = '\0';
    }
}

static int te_skip_tagbody(te_status *status)
{
    char c;
    int slash_flag = 0;

    while ((c = *(status->p_src++)) && (c != '>')){
        slash_flag = (c == '/') ? 1 : 0;
    }
    return slash_flag;
}

static void te_copy_tagbody(te_status *status)
{
    char c;
    int in_quote = 0;

    while ((c = *(status->p_src++)) && (in_quote || (c != '>'))){
        if (c == '<') {
            te_puts(status, "&lt;");
        } else if (c == '>') {
            te_puts(status, "&gt;");
        } else {
            if (c == in_quote) {
                in_quote = 0;
            } else if ((! in_quote) && (c == '\"') || (c == '\'')) {
                in_quote = c;
            }
            te_putc(status, c);
        }
    }
}

static void te_parse_a(te_status *status)
{
    char elmname[BUFSIZE];
    char value[BUFSIZE];

    while (1){
        te_skip_space(status);
        if (*(status->p_src) == '\0') return;
        if (*(status->p_src) == '>') {
            status->p_src++;
            return;
        }
        te_parse_name(status, elmname, BUFSIZE - 1);
        value[0] = '\0';
        te_skip_space(status);
        if (*(status->p_src) == '=') {
            status->p_src++;
            te_skip_space(status);
            te_parse_elmvalue(status, value, BUFSIZE - 1);
        }
        if ((strcasecmp(elmname, "href") == 0) ||
            (strcasecmp(elmname, "name") == 0) ) {
            te_putc(status, ' ');
            te_puts(status, elmname);
            if (value[0]) {
                te_putc(status, '=');
                te_puts(status, value);
            }
        }
    }
}

static void te_parse_tag(te_status *status)
{
    char buf[BUFSIZE];

    te_skip_space(status);
    te_parse_tagname(status, buf, BUFSIZE - 1);
    if (strcasecmp(buf, "a") == 0) {
        te_putc(status, '<');
        te_puts(status, buf);
        te_parse_a(status);
        te_putc(status, '>');
    } else if ((strcasecmp(buf, "br") == 0) ||
               (strcasecmp(buf, "/a") == 0) ||
               (strcasecmp(buf, "strong") == 0) ||
               (strcasecmp(buf, "/strong") == 0) ) {
        te_putc(status, '<');
        te_puts(status, buf);
        if (te_skip_tagbody(status)) te_puts(status, " /");
        te_putc(status, '>');
    } else {
        te_puts(status, "&lt;");
        te_puts(status, buf);
        te_copy_tagbody(status);
        te_puts(status, "&gt;");
    }
}

static void te_parse_plain(te_status *status)
{
    char c;

    while ((c = *(status->p_src++)) && (status->size > 0)) {
        if (c == '<') {
            te_parse_tag(status);
        } else {
            te_putc(status, c);
        }
    }
}

void tagescape(char *dest, char *src, int size)
{
    te_status status_buf;

    status_buf.p_src = src;
    status_buf.p_dest = dest;
    status_buf.size = size;
    te_parse_plain(&status_buf);
    *(status_buf.p_dest) = '\0';
}


/* test */

char sample_input1[] = "<a href='www.google.com'>link</a> <blink>and</blink> <strong onClick='alert(\"NG\")'>click<br/>me!</strong>'";

char sample_input2[] = "<script foo=\"<script>alert('bar')</script>\">alert('foo')</script>";

char sample_input3[] = "<script foo=\"<a href='link'>link</a>\">alert('foo')</script>";

char sample_input4[] = "<a href='www.g>oogle.com'>link</a>";

char outbuf[MAXDATASIZE];

int main()
{
    tagescape(outbuf, sample_input1, MAXDATASIZE - 1);
    puts(outbuf);
    tagescape(outbuf, sample_input2, MAXDATASIZE - 1);
    puts(outbuf);
    tagescape(outbuf, sample_input3, MAXDATASIZE - 1);
    puts(outbuf);
    tagescape(outbuf, sample_input4, MAXDATASIZE - 1);
    puts(outbuf);
}

 | HOME | 

Categories

Recent Entries

Recent Comments

Recent Trackbacks

Appendix

emasaka

emasaka

フリーター。
連絡先はこのへん

Monthly