<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2japanesefull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
    <channel>
        <title>PC日記</title>
        <link>http://www.wizard-limit.net/mt/pc/</link>
        <description>PCに関するもろもろもろ・・・</description>
        <language>ja</language>
        <copyright>Copyright 2010</copyright>
        <lastBuildDate>Mon, 25 Jan 2010 22:46:04 +0900</lastBuildDate>
        <generator>http://www.sixapart.com/movabletype/</generator>
        <docs>http://www.rssboard.org/rss-specification</docs>
        
        <atom:link rel="hub" href="http://pubsubhubbub.appspot.com" />
        
        <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/wizard-limit/mt/pc" /><feedburner:info uri="wizard-limit/mt/pc" /><item>
            <title>apcupsdが動かない</title>
            <description>最近あまりcactiのグラフとか細かくチェックしていなかったんだけど、久しぶりに見たらUPSの状態がグラフに出ていない。&lt;br/&gt;
なんでだろーと思って、グラフの元ネタを作っているapcaccessコマンドをたたいて見ると、なんとapcupsdが起動していないようだ。&lt;br/&gt;
/usr/local/etc/rc.d/apcupsd start でも起動しないので、/var/log/messageを見てみると、
&lt;pre class="textfile"&gt;
Jan 24 19:02:49 sv apcupsd[10014]: apcupsd FATAL ERROR in generic-usb.c at line 636 Cannot find UPS device -- For a link to detailed USB trouble shooting information, please see &amp;lt;http://www.apcupsd.com/support.html&amp;gt;.
Jan 24 19:02:49 sv apcupsd[10014]: apcupsd error shutdown completed
&lt;/pre&gt;
のようなエラーが出ている。&lt;br/&gt;
エラーメッセージでぐぐると、&lt;a href="http://groups.google.co.jp/group/lucky.freebsd.stable/browse_thread/thread/2db7d22a0353cfcf?pli=1"&gt;USB problems on 8.0-STABLE - lucky.freebsd.stable | Google グループ&lt;/a&gt;と言うページを発見したが、英語が不如意なせいで読んでも良くわからない。usbconfig や dmesg の出力を見て、apcupsd.conf の DEVICE の行に ugen1.2とか書いてみても駄目だった。&lt;br/&gt;
で、一日置いて再度読んで見ると、「&lt;a href="http://groups.google.co.jp/group/lucky.freebsd.stable/browse_thread/thread/2db7d22a0353cfcf/baba022e19f9f087"&gt;新しいメッセージ&amp;gt;&lt;/a&gt;」と言うリンクを発見。なんと、1ページですべて表示しきれていなくて、2ページ目があった！&lt;br/&gt;
どうも、このGoogleグループって奴のpermalinkのルールが良くわからないので、該当のメッセージを以下に引用しておくけど、
&lt;blockquote&gt;
 Steve Randall     	&lt;br/&gt;
&lt;br/&gt;
A possibility occurs to me that I think nobody has yet mentioned. If
you still have the obsolete usbdevs command on your system, is it
possible you also still have the obsolete devel/libusb port installed?
It conflicts with the libusb in the base system, causing just the sorts
of problems you are experiencing. 
&lt;/blockquote&gt;

要は、以前portsから入れた devel/libusb が 8.0 のベースシステムに入ったlibusbとconflictしてるって言う話らしい。&lt;br/&gt;
この後の投稿で、devel/libusbを削除したらうまくいったと言うものもあったので、pkg_deinstall -f libusb してから、依存していたsane-backendsとapcupsdを再インストールした。&lt;br/&gt;
無事に、apctestもapcupsdも動いて、当然apcaccessも動くようになった。&lt;br/&gt;
ん～、英語はわからんとか言わないで、とりあえず次のページくらいは見ておくもんですね。&lt;br/&gt;
&lt;br/&gt;
ところで、sanedってどうやって起動するんだっけ？/usr/local/etc/rc.d/にはスクリプトがないんだけど・・・。&lt;br/&gt;
→man sanedしたら inetd が起動するんだった。/etc/inetd.conf に書いてあるのでそのまま動くはず！</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/iPHf7TdkUG4/004067.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/004067.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">FreeBSD</category>
            
            
            <pubDate>Mon, 25 Jan 2010 22:46:04 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/004067.html</feedburner:origLink></item>
        
        <item>
            <title>今日のはまった</title>
            <description>tig.rb と言うtwitter とircのgatewayを使っているのだけれど、バージョンアップしたらしいので svn up してみても何も起きない。&lt;br/&gt;
作者さんのページ&lt;a href="http://subtech.g.hatena.ne.jp/cho45/20070415/1176631923"&gt;tig.rb (twitter irc gareway) - 冬通りに消え行く制服ガールは、夢物語にリアルを求めない。 - subtech&lt;/a&gt;を見ても、しばらく意味が理解できなかったのだけれど、どうもlowreal.netからcodereposに移動して、その後githubに移動したらしい。私はcodereposを見ていたので古いままだったようだ。&lt;br/&gt;
さっそくgithubから git clone して、tig.rbとwig.rb(wassr と irc の gateway)を起動してみるが、tig.rbの方がopensslのエラーでうまく動かない。&lt;br/&gt;
&lt;a href="http://twitter.com/otsune/status/7739650558"&gt;otsuneさんのつぶやき&lt;/a&gt;を見ていたので、早速 ports の security/ca_root_nss を更新してみたが、エラーは止まらない。&lt;br/&gt;
apache の SNIのためにportsから openssl を入れていたのが悪いのかと思って、portsのopensslを削除してみた(FreeBSD8になったときに、openssl 0.9.8kになったのでSNI対応になったため、portsの0.9.8lは削除しても良くなった)がやはり変わらず。
ports/security/ca_root_nss の Makefile を読んで見ると、/etc/ssl/cert.pem にリンクをはるなんてオプションがあるのを発見したので、手動で/usr/local/share/certs/ca-root-nss.crt からリンクを張ってみたら無事にtig.rbが起動した。&lt;br/&gt;
本来の手順としては、ports/security/ca_root_nss  で make config して、ETCSYMLINK にチェックを入れてやれば良いんだと思う。&lt;br/&gt;
しかし、/etc/ssl には元々のcert.pem は存在していなかったんだけど、ここにない場合(OSの標準の状態)はどこのファイルを見るんだろう？ひょっとしてOSの方をmake world すれば良かったんだろうか？&lt;br/&gt;
&lt;br/&gt;
&lt;br/&gt;
portsのopensslを削除した関係で、依存関係があったものをすべてコンパイルし直したので、ついでにportauditに警告されていたpostgresqlもバージョンアップすることに。&lt;br/&gt;
今まで入っていたのが8.4.0で、最新が8.4.2。3番目の数字が変わる分には、DBの再構築(dump/restore)は必要ないはずなので、そのままportupgradeした。&lt;br/&gt;
で、postgresqlを起動しようとしたら、かなり待たされた後に起動に失敗したと言われる。&lt;br/&gt;
logを見ると、
&lt;pre class="textfile"&gt;
FATAL:  database files are incompatible with server
DETAIL:  The database cluster was initialized with HAVE_INT64_TIMESTAMP but the server was compiled without HAVE_INT64_TIMESTAMP.
HINT:  It looks like you need to recompile or initdb.
&lt;/pre&gt;
なんて出てる。どうも、DBはINT64のTIMESTAMPが使えるようになってるけど、serverはそう言うオプションでコンパイルされていないらしい。&lt;br/&gt;
変えた覚えないんだけどな～と思いながら、ports/databases/postgresql84-server で make config すると、果たして INTDATE - Builds with 64-bit date/time type と言うオプションがあったので有効にしてやったら無事に起動するようになった。&lt;br/&gt;
このオプションが有効じゃない場合、timestampは何が使われるんだろうか？</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/ME0wU-YUOGg/004049.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/004049.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">FreeBSD</category>
            
            
            <pubDate>Thu, 14 Jan 2010 23:16:01 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/004049.html</feedburner:origLink></item>
        
        <item>
            <title>ホームビデオを公開するには</title>
            <description>親族や親しい友人だけに見てもらえるように、認証付きのページで育児ブログを公開している。&lt;br/&gt;
文章や写真は普通にMovableTypeの枠組みで公開できるけど、動画はそうはいかない。&lt;br/&gt;
Youtube等の動画共有サイトは、まさに共有をメインに考えられているので、一部の人に限定公開すると言う用途に向かない。&lt;br/&gt;
だいたいのサイトでは、閲覧者がメンバにならないと限定公開の対象にできないからだ。&lt;br/&gt;
しかし、育児ブログを見て欲しい方はあまりパソコンやネットに詳しくないことが多いので、「○○サイトのアカウントを取ってください」と言っても通じないし、Youtubeで動画毎に公開範囲を決めるやり方は面倒くさい。&lt;br/&gt;
そこで、eyeVioと言うサイトならプレイリスト単位でパスワードによる認証がかけられるので利用していたのだが、ここもいまいち使い勝手が悪い。&lt;br/&gt;
&lt;br/&gt;
どうせ自宅サーバでブログをやっているのだから、動画もここに置けないかと思って調べてみた。&lt;br/&gt;
公開する動画は、SANYOのxactiで撮った MP4 か、iPhoneのmov。どちらも、そのままaタグで貼っても普通の人は見づらい。(まあ、movはQuicktimeが入ってれば見られるけど、おじいちゃんおばあちゃんだと入ってない場合が多いんじゃないかな)&lt;br/&gt;
そうなると、Youtubeやニコニコ動画がやっているようにflash playerで再生できる形のビデオにしたい。&lt;br/&gt;
いろいろなサイトを参照した結果、どうにかしてflv形式の動画ファイルを作成し、フリーのflv playerをwebページに埋め込むと言うのが現実的らしい。&lt;br/&gt;
&lt;br/&gt;
まずは、flv形式への変換だが、&lt;a href="http://lapis.clover.vc/"&gt;FLV/MP4エンコードスレ 支援サイト&lt;/a&gt;から「mencoder_vp6set」と言うのを持ってきて、中に入っている「FLV4enc_D&amp;D_2pass_4：3.bat」 をコピーして
&lt;pre class="textfile"&gt;
set EXTOPT=-vf flip,scale=512:384 -sws 9 -af resample=44100
&lt;/pre&gt;
の行を
&lt;pre class="textfile"&gt;
set EXTOPT=-vf flip -sws 9 -af resample=44100
&lt;/pre&gt;
のように書き換えた。私のxactiの動画は 640x480で、特にサイズを変更したくなかったので。&lt;br/&gt;
後は、explorerでこのバッチファイルにMP4をドラッグ＆ドロップして、audioのbitrateを入力するとvp6 encoderのダイアログが開くので適当に設定する。私が修正したのは bitrate だけで、デフォルトの300だと640x480の解像度ではきついので、600にしてみた。&lt;br/&gt;
この設定で、2分27秒のMP4(H.264/AAC/3.11Mbit/s) 54.9MBが、11.9MBのflvになった。&lt;br/&gt;
&lt;br/&gt;
次に、このファイルをサーバに置いて、blogのエントリにflv playerを配置する。&lt;br/&gt;
flv playerは、&lt;a href="http://flowplayer.org/index.html"&gt;Flow Player&lt;/a&gt;と言うのを利用することにした。&lt;br/&gt;
free版をダウンロードし、中に入っているswf二つとjavascriptのファイルをサーバの適当な場所に置く。&lt;br/&gt;
続いて、blogのテンプレートをいじって今置いたjavascriptのファイルをscriptタグで読み込むようにする。&lt;br/&gt;
後は、blogのエントリに以下のような記述を書くと、playerが配置される。
&lt;pre class="textfile"&gt;
&amp;lt;a href="&amp;lt;$MTBlogArchiveURL$&amp;gt;videos/&lt;i&gt;ファイル名&lt;/i&gt;.flv"
   style="display:block;width:640px;height:480px"
   id="&lt;i&gt;ユニークID&lt;/i&gt;"&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;script&amp;gt;
   flowplayer("&lt;i&gt;ユニークID&lt;/i&gt;", "/flowplayer/flowplayer-3.1.5.swf", {clip: {autoPlay: false, autoBuffering: true}});
&amp;lt;/script&amp;gt;
&lt;/pre&gt;

a href= に動画ファイルを置いたURLを書き、styleに動画のサイズを指定。&lt;br/&gt;
id にはユニークなIDを指定する。(同一エントリに複数の動画を置いたり、複数エントリに動画がある場合の MainIndex テンプレートで衝突が起きないため)</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/z7D0Xd8EU4o/004022.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/004022.html</guid>
            
            
            <pubDate>Tue, 22 Dec 2009 06:59:27 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/004022.html</feedburner:origLink></item>
        
        <item>
            <title>MovableType 5.0 のカスタマイズ</title>
            <description>新しいバージョンのMTをインストールすると、以下のカスタマイズを実施する。&lt;br/&gt;
この辺は、昔のMTの方が良かったな～と思う部分だ。&lt;br/&gt;
&lt;br/&gt;
&lt;h3&gt;1. 画像をアップロードする場所&lt;/h3&gt;
画像をアップロードする場所は、デフォルトでblogのディレクトリ。この場所を決めるのは、tmpl/cms/include/asset_upload.tmpl。このファイルを、alt-tmpl/cms/include/ にコピーして、以下の修正をする。
&lt;pre class="textfile"&gt;
*** tmpl/cms/include/asset_upload.tmpl  2009-09-11 18:10:24.000000000 +0900
--- alt-tmpl/cms/include/asset_upload.tmpl      2009-11-29 15:10:50.000000000 +0900
***************
*** 168,174 ****
              &amp;lt;select name="site_path" id="site_path" onchange="setExtraPath(this)"&amp;gt;
                  &amp;lt;option value="1"&amp;gt;&amp;amp;#60;&amp;lt;__trans phrase="Site Root"&amp;gt;&amp;amp;#62;&amp;lt;/option&amp;gt;
              &amp;lt;mt:if name="enable_archive_paths"&amp;gt;
!                 &amp;lt;option value="0"&amp;lt;mt:if name="archive_path"&amp;gt; selected="selected"&amp;lt;/mt:if&amp;gt;&amp;gt;&amp;amp;#60;&amp;lt;__trans phrase="Archive Root"&amp;gt;&amp;amp;#62;&amp;lt;/option&amp;gt;
              &amp;lt;/mt:if&amp;gt;
              &amp;lt;mt:if name="extra_paths"&amp;gt;
                  &amp;lt;mt:loop name="extra_paths"&amp;gt;
--- 168,174 ----
              &amp;lt;select name="site_path" id="site_path" onchange="setExtraPath(this)"&amp;gt;
                  &amp;lt;option value="1"&amp;gt;&amp;amp;#60;&amp;lt;__trans phrase="Site Root"&amp;gt;&amp;amp;#62;&amp;lt;/option&amp;gt;
              &amp;lt;mt:if name="enable_archive_paths"&amp;gt;
!                 &amp;lt;option value="0" selected="selected"&amp;gt;&amp;amp;#60;&amp;lt;__trans phrase="Archive Root"&amp;gt;&amp;amp;#62;&amp;lt;/option&amp;gt;
              &amp;lt;/mt:if&amp;gt;
              &amp;lt;mt:if name="extra_paths"&amp;gt;
                  &amp;lt;mt:loop name="extra_paths"&amp;gt;
***************
*** 176,182 ****
                  &amp;lt;/mt:loop&amp;gt;
              &amp;lt;/mt:if&amp;gt;
              &amp;lt;/select&amp;gt;
!             / &amp;lt;input type="text" name="extra_path" id="extra_path" class="extra-path" value="&amp;lt;mt:var name="extra_path" escape="html"&amp;gt;" /&amp;gt;
              &amp;amp;nbsp;&amp;lt;a href="javascript:void(0);" mt:command="open-folder-selector"&amp;gt;&amp;lt;__trans phrase="Choose Folder"&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;/mtapp:setting&amp;gt;
      &amp;lt;/mt:if&amp;gt;
--- 176,182 ----
                  &amp;lt;/mt:loop&amp;gt;
              &amp;lt;/mt:if&amp;gt;
              &amp;lt;/select&amp;gt;
!             / &amp;lt;input type="text" name="extra_path" id="extra_path" class="extra-path" value="images" /&amp;gt;
              &amp;amp;nbsp;&amp;lt;a href="javascript:void(0);" mt:command="open-folder-selector"&amp;gt;&amp;lt;__trans phrase="Choose Folder"&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;/mtapp:setting&amp;gt;
      &amp;lt;/mt:if&amp;gt;
&lt;/pre&gt;
これ、ソース的には mt の変数 archive_path, extra_path に依存しているコードの様なので、これらの変数が適切に設定されていれば動きそうなもんなんだけど、その辺の仕組みがわからないので直接テンプレートをいじってしまっている。&lt;br/&gt;
&lt;h3&gt;2. 画像の表示とか&lt;/h3&gt;
これは、MTのバージョン云々じゃなくて、細かい趣味の問題。ひとつは、imgタグに border="0" を付けること。(CSSでやれって話ではある)、もう一つは画像をクリックしたときに開くウィンドウの属性が気に入らないので修正、最後は、サムネイルのデフォルトのサイズの修正。&lt;br/&gt;
そもそも、昔のMTはサムネイルのサイズを、pixelだけじゃなくてpercentで指定できたのに、今のはできないのが気に入らない。&lt;br/&gt;
&lt;pre class="textfile"&gt;
*** lib/MT/Asset/Image.pm.orig  2009-11-24 09:51:41.000000000 +0900
--- lib/MT/Asset/Image.pm       2009-11-29 15:25:49.000000000 +0900
***************
*** 314,326 ****
              my $link =
                $thumb
                ? sprintf(
!                 '&amp;lt;img src="%s" %s alt="%s" %s /&amp;gt;',
                  MT::Util::encode_html( $thumb-&amp;gt;url ),   $dimensions,
                  MT::Util::encode_html( $asset-&amp;gt;label ), $wrap_style
                )
                : MT-&amp;gt;translate('View image');
              $text = sprintf(
! q|&amp;lt;a href="%s" onclick="window.open('%s','popup','width=%d,height=%d,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"&amp;gt;%s&amp;lt;/a&amp;gt;|,
                  MT::Util::encode_html( $popup-&amp;gt;url ),
                  MT::Util::encode_html( $popup-&amp;gt;url ),
                  $asset-&amp;gt;image_width,
--- 314,326 ----
              my $link =
                $thumb
                ? sprintf(
!                 '&amp;lt;img src="%s" %s alt="%s" %s border="0" /&amp;gt;',
                  MT::Util::encode_html( $thumb-&amp;gt;url ),   $dimensions,
                  MT::Util::encode_html( $asset-&amp;gt;label ), $wrap_style
                )
                : MT-&amp;gt;translate('View image');
              $text = sprintf(
! q|&amp;lt;a href="%s" onclick="window.open('%s','popup','width=%d,height=%d,scrollbars=yes,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"&amp;gt;%s&amp;lt;/a&amp;gt;|,
                  MT::Util::encode_html( $popup-&amp;gt;url ),
                  MT::Util::encode_html( $popup-&amp;gt;url ),
                  $asset-&amp;gt;image_width,
***************
*** 331,337 ****
          else {
              if ( $param-&amp;gt;{thumb} ) {
                  $text = sprintf(
!                     '&amp;lt;a href="%s"&amp;gt;&amp;lt;img alt="%s" src="%s" %s %s /&amp;gt;&amp;lt;/a&amp;gt;',
                      MT::Util::encode_html( $asset-&amp;gt;url ),
                      MT::Util::encode_html( $asset-&amp;gt;label ),
                      MT::Util::encode_html( $thumb-&amp;gt;url ),
--- 331,337 ----
          else {
              if ( $param-&amp;gt;{thumb} ) {
                  $text = sprintf(
!                     '&amp;lt;a href="%s"&amp;gt;&amp;lt;img alt="%s" src="%s" %s %s border="0" /&amp;gt;&amp;lt;/a&amp;gt;',
                      MT::Util::encode_html( $asset-&amp;gt;url ),
                      MT::Util::encode_html( $asset-&amp;gt;label ),
                      MT::Util::encode_html( $thumb-&amp;gt;url ),
***************
*** 386,392 ****
        ( $blog-&amp;gt;image_default_wunits || 'pixels' ) eq $_ ? 1 : 0
        for qw(percent pixels);
      $param-&amp;gt;{thumb_width} = $blog-&amp;gt;image_default_width
!       || $asset-&amp;gt;image_width
        || 0;

      return $app-&amp;gt;build_page( 'dialog/asset_options_image.tmpl', $param );
--- 386,392 ----
        ( $blog-&amp;gt;image_default_wunits || 'pixels' ) eq $_ ? 1 : 0
        for qw(percent pixels);
      $param-&amp;gt;{thumb_width} = $blog-&amp;gt;image_default_width
!       || $asset-&amp;gt;image_width / 4
        || 0;

      return $app-&amp;gt;build_page( 'dialog/asset_options_image.tmpl', $param );
&lt;/pre&gt;
&lt;h3&gt;3. bookmarklet&lt;/h3&gt;
昔のMTは、bookmarkletからポストしようとすると、blockquoteにしてくれたり、トラックバック先が自動で入力されたり、blogが選べたり、他にもいろいろオプションがあったんだけど、今のはできない。&lt;br/&gt;
せめて、blogのURLへのリンクやページタイトルと、選択部分のblockquoteくらいやりたくて、以下の修正。
&lt;pre class="textfile"&gt;
*** lib/MT/CMS/Entry.pm.ORIG    2009-11-29 21:06:37.000000000 +0900
--- lib/MT/CMS/Entry.pm 2009-11-29 21:10:16.000000000 +0900
***************
*** 2223,2229 ****
          or return $app-&amp;gt;error($app-&amp;gt;translate('Can\'t load blog #[_1].', $blog_id));
      my %args    = ( '_type' =&amp;gt; $type, blog_id =&amp;gt; $blog_id, qp =&amp;gt; 1 );
      my $uri = $app-&amp;gt;base . $app-&amp;gt;uri( 'mode' =&amp;gt; 'view', args =&amp;gt; \%args );
!     my $script = qq!javascript:d=document;w=window;t='';if(d.selection)t=d.selection.createRange().text;else{if(d.getSelection)t=d.getSelection();else{if(w.getSelection)t=w.getSelection()}}void(w.open('$uri&amp;amp;title='+encodeURIComponent(d.title)+'&amp;amp;text='+encodeURIComponent(d.location.href)+encodeURIComponent('&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;')+encodeURIComponent(t),'_blank','scrollbars=yes,status=yes,resizable=yes,location=yes'))!;
      # Translate the phrase here to avoid ActivePerl DLL bug.
      $app-&amp;gt;translate('&amp;lt;a href="[_1]"&amp;gt;QuickPost to [_2]&amp;lt;/a&amp;gt; - Drag this link to your browser\'s toolbar, then click it when you are visiting a site that you want to blog about.', encode_html($script), encode_html($blog-&amp;gt;name));
  }
--- 2223,2229 ----
          or return $app-&amp;gt;error($app-&amp;gt;translate('Can\'t load blog #[_1].', $blog_id));
      my %args    = ( '_type' =&amp;gt; $type, blog_id =&amp;gt; $blog_id, qp =&amp;gt; 1 );
      my $uri = $app-&amp;gt;base . $app-&amp;gt;uri( 'mode' =&amp;gt; 'view', args =&amp;gt; \%args );
!     my $script = qq!javascript:d=document;w=window;t='';if(d.selection)t=d.selection.createRange().text;else{if(d.getSelection)t=d.getSelection();else{if(w.getSelection)t=w.getSelection()}}void(w.open('$uri&amp;amp;title='+encodeURIComponent(d.title)+'&amp;amp;link='+encodeURIComponent(d.location.href)+'&amp;amp;text='+encodeURIComponent(t),'_blank','scrollbars=yes,status=yes,resizable=yes,location=yes'))!;
      # Translate the phrase here to avoid ActivePerl DLL bug.
      $app-&amp;gt;translate('&amp;lt;a href="[_1]"&amp;gt;QuickPost to [_2]&amp;lt;/a&amp;gt; - Drag this link to your browser\'s toolbar, then click it when you are visiting a site that you want to blog about.', encode_html($script), encode_html($blog-&amp;gt;name));
  }
*** lib/MT/CMS/Common.pm.ORIG   2009-11-29 21:24:34.000000000 +0900
--- lib/MT/CMS/Common.pm        2009-11-29 21:25:10.000000000 +0900
***************
*** 515,520 ****
--- 515,527 ----
              my $data = $q-&amp;gt;param($_);
              $q-&amp;gt;param( $_, $data );
          }
+       my $title = $q-&amp;gt;param('title');
+       my $link = scalar $q-&amp;gt;param('link');
+       my $text = $q-&amp;gt;param('text');
+       $text = sprintf qq(&amp;lt;blockquote&amp;gt;\n&amp;lt;div class="quote-head"&amp;gt;&amp;lt;a title="%s" href="%s"&amp;gt;%s&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;\n\n%s\n&amp;lt;/blockquote&amp;gt;), $title, $link, $title, $text;
+       $q-&amp;gt;param('title', '');
+       $q-&amp;gt;param('link', '');
+       $q-&amp;gt;param('text', $text);
      }

      $param{autosave_frequency} = $app-&amp;gt;config-&amp;gt;AutoSaveFrequency;
&lt;/pre&gt;
ダッシュボードのデザインは4よりは5の方が趣味にあっているので、使い続けようと思うけど、とっくの昔に自前サーバでblogをやると言う時代は終わっているのかも知れないな～と思った。</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/3G9aAPn1RXM/003992.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003992.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">MovableType</category>
            
            
            <pubDate>Sun, 29 Nov 2009 21:31:56 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003992.html</feedburner:origLink></item>
        
        <item>
            <title>MovableType 5.0</title>
            <description>ここのblogシステムはMovableTypeを使っているのだけれど、最近5.0がリリースされたので早速インストールしてみた。&lt;br/&gt;
まず、5.0からは正式なサポートがMySQLだけになって、SQLiteとPostgreSQLは使えなくなってしまったらしい。&lt;br/&gt;
私はMySQLよりもPostgreSQLが好きなので、どうしようかと悩んでいたが、どうせperlのDBDとかDBIとかその辺のパッケージを使っているはずなので、PostgreSQLのまま行ってみることにした。&lt;br/&gt;
ためしに、mt-check.cgiを動かして見ると、相変わらずSQLiteとかPostgreSQLのパッケージのチェックもしているから行けるのではないかと思ったのだ。&lt;br/&gt;
まずは、公式のインストールガイドの「&lt;a href="http://www.movabletype.jp/documentation/mt5/upgrade/copy-mt4-to-mt5.html"&gt;既存のデータベースを残す方式のアップグレード&lt;/a&gt;」を参考に、別のDB、別のパスでインストールすることにする。&lt;br/&gt;
MT4をインストールしているディレクトリの横に mt5 と言う名前で一式を置き、mt-config.cgiをmtから持ってくる。&lt;br/&gt;
DBは、mtと言うDBからmt5と言うdbにコピー。PostgreSQLの場合は、
&lt;pre class="commandline"&gt;
# createdb -T mt mt5
&lt;/pre&gt;
でそのまんまコピーができる。&lt;br/&gt;
mt5/mt.cgi にアクセスすると、アップグレードの確認になるので、そのまま進む。&lt;br/&gt;
無事に終わって再度mt.cgiにアクセスすると、新しいダッシュボードにアクセスできる。&lt;br/&gt;
ここで、Web site と言うのがあるはずなのに、何もなくって、新しく作るしか選べない。&lt;br/&gt;
新しいものを作ろうとすると、デフォルトの言語が英語になっている。&lt;a href="http://www.movabletype.jp/documentation/mt5/release/50.html"&gt;Movable Type 5.0 の変更点、注意事項、および既知の問題&lt;/a&gt;を見ると、mt-config.cgiに 「DefaultLanguage ja」を追加しろとあったので、追加してみたら日本語がデフォルトになった。&lt;br/&gt;
しかし、試しに新しいWeb siteを作って見たりしても、ブログが一個も出てこない。&lt;br/&gt;
&lt;a href="http://www.movabletype.jp/documentation/mt5/upgrade/website.html"&gt;アップグレード時のウェブサイト自動作成&lt;/a&gt;を見ると、勝手にウェブサイトができるように見える。&lt;br/&gt;
このドキュメントを見ると、サイトのURLからウェブサイト(?)の何かを決めるように見えるので、その辺が怪しいのかと思って、mt-config.cgiの StaticWebPath をフルのURLにして、StaticFilePath に絶対パスを書いてみたりしたが、効果なし。&lt;br/&gt;
しょうがないので、アップグレード周りのソースをつらつらと眺めていたら、lib/MT/Upgrade/v5.pm の中で、以下のような箇所が。
&lt;pre class="textfile"&gt;
sub upgrade_functions {
    return {
        #'v5_migrate_blog' =&amp;gt; {
        #    version_limit =&amp;gt; 5.0004,
        #    priority      =&amp;gt; 3.2,
        #    code          =&amp;gt; \&amp;amp;_v5_migrate_blog,
        #},
&lt;/pre&gt;
ここにある_v5_migrate_blog を読むと、そのまんまgeneric website の作成的な感じなので、このコメントを外して試して見たら、無事に移行ができた。&lt;br/&gt;
後は、pluginを移行して試しにリビルドしてみるが、動いている感じ。&lt;br/&gt;
これで本格的に移行できるかと思って、blog entryの編集画面に行ってみたら、本文が表示されない。&lt;br/&gt;
Firefoxだと編集領域にカーソルが行かなくて、IEだとカーソルが行くけど本文が出てない。&lt;br/&gt;
調べて見たら、&lt;a href="http://www.mattune.jp/memo/memo_movabletype/000081.html"&gt;MacでMT4の本文が編集できない事態が発生！？&lt;/a&gt;と言う記事を発見。&lt;br/&gt;
さきほど変更した StaticWebPath と StaticFilePath が悪かったらしい。&lt;br/&gt;
元のようにStaticWebPathだけにして、中身は /mt-static だけにする。&lt;br/&gt;
これでなんとなく動きそうな雰囲気なので、/mt5 から /mt にして、mt-config.cgiも直し、DBをコピーし直して MovableType 5.0 で運用を開始することにした。&lt;br/&gt;</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/pJ4HtxqKxXY/003991.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003991.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">MovableType</category>
            
            
            <pubDate>Sat, 28 Nov 2009 19:31:20 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003991.html</feedburner:origLink></item>
        
        <item>
            <title>クライアント認証ができなくなった</title>
            <description>&lt;a href="http://builder.japan.zdnet.com/news/story/0,3800079086,20402262,00.htm"&gt;Apacheが2.2.12からSNIに対応した&lt;/a&gt;と言うので、試してみようと思ったが、SNIに対応するにはopensslが0.9.8f以降でないといけないらしい。&lt;br/&gt;
FreeBSD 7.1のopensslは0.9.8eなので保留していたのだが、portsに0.9.8lが入っていたので試してみた。&lt;br/&gt;
portsからsecurity/opensslをインストールして、www/apache22を再インストールすると、勝手に-with-ssl=/usr/localとか言ってportsから入れた0.9.8lを認識してくれるようだ。&lt;br/&gt;
早速、以前作ってあった別名用のサーバ証明書を見るようにssl.confを書き換えてみたが、
&lt;pre class="textfile"&gt;
SSL peer was unable to negotiate an acceptable set of security parameters.

(エラーコード: ssl_error_handshake_failure_alert)
&lt;/pre&gt;
なんてエラーで繋がらない。(Firefoxの場合)&lt;br/&gt;
どうも、SSLVerifyClient require の指定があるとうまくいかないようだ。&lt;br/&gt;
別の環境に一からapacheをインストールして、証明書関連も作り直して試してみたところ、以下のことがわかった。
&lt;pre class="textfile"&gt;
Listen *:443
NameVirtualHost *:443
&amp;lt;VirtualHost *:443&amp;gt;
ServerName hoge.example.com
SSLEngine on
SSLCertificateFile /usr/local/etc/apache22/ssl/server.crt
SSLCertificateKeyFile /usr/local/etc/apache22/ssl/server.key
SSLCertificateChainFile /usr/local/etc/apache22/ssl/ca.crt
SSLCACertificateFile /usr/local/etc/apache22/ssl/ca.crt
&amp;lt;Location /test&amp;gt;
SSLVerifyClient require
&amp;lt;/Location&amp;gt;
&amp;lt;/VirtualHost&amp;gt;
&lt;/pre&gt;
のように、Locationの中にSSLVerifyClient require があるとそのURLでのみ失敗する。Locationの外側(サイト全体)に書いてやると、ちゃんとクライアント認証した上で接続できる。&lt;br/&gt;
これが、proxyがある場合とない場合でも微妙に挙動が違うようだが整理しきれていない。&lt;br/&gt;
&lt;a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=12355"&gt;Bug 12355 -  POST incompatible w/ renegotiate https: connection&lt;/a&gt;と言うのが見つかったが、この問題自体は2.2では修正済みとも読める。&lt;br/&gt;
&lt;a href="http://slashdot.jp/~Ryo.F/journal/366192"&gt;WebDAV/Apache/HTTPSクライアント認証&lt;/a&gt;と言うのも見つけたので試してみたが効かないようだ。&lt;br/&gt;
&lt;a href="http://mlog.euqset.org/archives/debian-users/53339.html"&gt;[debian-users:53339] [Translate] [SECURITY] [DSA-1934-1] New apache2 packages fix severalissues&lt;/a&gt;みたいな話も見つけたが、関係あるだろうか？&lt;br/&gt;
&lt;br/&gt;
他にも、SSLOptionsに+OptRenegotiateを付けてみたり、CA.shを使って証明書を作り直したりしてみたが改善せず。&lt;br/&gt;
wiresharkでパケットを覗いてみたりもしたがさっぱりわからないので、とりあえずお手上げ状態です。&lt;br/&gt;
&lt;br/&gt;</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/ghF2qfDmxFA/003987.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003987.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Network</category>
            
            
            <pubDate>Wed, 25 Nov 2009 12:51:26 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003987.html</feedburner:origLink></item>
        
        <item>
            <title>UPS交換</title>
            <description>結局次の日もUPSが落ちたので、諦めてamazonで注文。&lt;br/&gt;
昨日注文して今日届いたので、お急ぎ便必要ないじゃんって感じ。&lt;br/&gt;
前回はyodobashi.comで14,500円だったけど、今回はamazonで8,790円。APCでバッテリーだけ注文(8,610円)しても良かったんだけど、いまいち挙動が怪しかったので本体ごと買うことにした。&lt;br/&gt;
数日運用して問題がなければ古いのの処分を考えないといけない。鉛蓄電池は普通に捨てられないので、APCに送り返すか、ハードオフみたいなところに持っていくといいらしい。&lt;br/&gt;

&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=wizardlimit-22&amp;o=9&amp;p=8&amp;l=as1&amp;m=amazon&amp;f=ifr&amp;md=1X69VDGQCMF7Z30FM082&amp;asins=B0000AG7HB" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/b7LFHQ9Qu5U/003971.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003971.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">FreeBSD</category>
            
            
            <pubDate>Tue, 10 Nov 2009 23:26:13 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003971.html</feedburner:origLink></item>
        
        <item>
            <title>UPS働く？</title>
            <description>突然ネットが繋がらなくなったと家人が言うので、マシンルームに行ってみるとサーバが落ちている。&lt;br/&gt;
電源ボタンを押しても、後ろの主電源を触ってもうんともすんとも言わない。&lt;br/&gt;
電源かマザーでも逝ったか！？と青くなったんだけど、ふと横を見たらUPSの電源LEDがついていない。&lt;br/&gt;
そこで、UPSの電源を入れると、無事にサーバも立ち上がった。&lt;br/&gt;
しかし、UPSがぴーぴーぴーぴーうるさい。マニュアルを見ると、バッテリー運転に切り替わっているらしい。&lt;br/&gt;
で、商用電源が正常なのにバッテリー運転をする場合、と言うところを見ると、「サーキットブレーカがトリップしている可能性があります。ただちに接続機器（負荷）を停止し、本装置をオフにしてください。接続機器（負荷）を減らしてからサーキットブレーカを押し戻してリセットしてください。」だそうなので、再度サーバをシャットダウンしてUPSの電源をOFFにして、ブレーカをリセットした。&lt;br/&gt;
サーバを立ち上げてログを見ると、以下のような感じ。&lt;br/&gt;
/var/log/messages
&lt;pre class="textfile"&gt;
Nov  4 21:55:10 sv apcupsd[1080]: Reached remaining time percentage limit on batteries.
Nov  4 21:55:10 sv apcupsd[1080]: Initiating system shutdown!
Nov  4 21:55:10 sv apcupsd[1080]: User logins prohibited
Nov  4 21:55:10 sv apcupsd[1080]: Attempting to kill the UPS power!
Nov  4 21:55:10 sv shutdown: halt by root: apcupsd initiated shutdown
Nov  4 21:55:38 sv kernel: pid 1913 (asterisk), uid 0: exited on signal 11 (core dumped)
Nov  4 21:55:38 sv kernel: encode_long: negative value -52 in accounting record
Nov  4 21:55:43 sv rc.shutdown: 30 second watchdog timeout expired. Shutdown terminated.
Nov  4 21:55:43 sv init: /bin/sh on /etc/rc.shutdown terminated abnormally, going to single user mode
Nov  4 21:55:43 sv syslogd: exiting on signal 15
&lt;/pre&gt;
/var/log/apcupsd.events
&lt;pre class="textfile"&gt;
Wed Nov 04 21:22:30 JST 2009  Power failure.
Wed Nov 04 21:22:36 JST 2009  Running on UPS batteries.
Wed Nov 04 21:55:10 JST 2009  Reached remaining time percentage limit on batteries.
Wed Nov 04 21:55:10 JST 2009  Initiating system shutdown!
Wed Nov 04 21:55:10 JST 2009  User logins prohibited
Wed Nov 04 21:55:10 JST 2009  Attempting to kill the UPS power!
Wed Nov 04 21:55:43 JST 2009  apcupsd exiting, signal 15
Wed Nov 04 21:55:43 JST 2009  apcupsd shutdown succeeded
&lt;/pre&gt;

停電があったわけではないので、過負荷か何かでUPSのブレーカが落ちてバッテリーモードに入り、電池がなくなってシャットダウンしたらしい。いまいち綺麗に落ちれてないみたいだけど。&lt;br/&gt;
UPSも買ってから1年半なので、バッテリーの寿命の2年までそろそろかな？ログからみると、バッテリーで30分運用できるみたいなので、まだ行けそうな気はするけど。&lt;br/&gt;
&lt;br/&gt;
おまけ。UPSの状態のcactiグラフ。&lt;br/&gt;
&lt;span class="mt-enclosure mt-enclosure-image" style="display: inline;"&gt;&lt;img alt="graph_47_5.png" src="http://www.wizard-limit.net/mt/pc/archives/images/graph_47_5.png" width="603" height="226" class="mt-image-none" style="" /&gt;&lt;/span&gt;&lt;br clear="all" /&gt;
あれ、充電が上がってないな。</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/Sj6W4ZQoECA/003957.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003957.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">FreeBSD</category>
            
            
            <pubDate>Wed, 04 Nov 2009 22:35:50 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003957.html</feedburner:origLink></item>
        
        <item>
            <title>CustomFeed::MixiScraperでmixiの画像をローカル保存</title>
            <description>iPhoneで快適にfastladderが見れるようになったのだが、mixiの画像がうまく見れない。&lt;br/&gt;
これは、以前やった自前改造で、mixiの画像はobjectタグでmixiの画像表示ページへリンクするようにしていたのだけれど、iPhoneのSafariはページ内のobjectタグにスクロールバーが出ないので、画像の一部しか表示されない。&lt;br/&gt;
そこで、WWW::Mixi::ScraperとPlagger::Plugin::CustomFeed::MixiScraperに手を入れて、画像をローカル保存するようにして、fastladderから見れるようにしてみた。&lt;br/&gt;
しっかし、perl4のときにちょっとかじったくらいの知識だと、WWW::Mixi::Scraperのソースは暗号にしか見えない。YAPCの記事なんか見ててもうらやましくてしょうがないので、一度perlを勉強しなおした方が良いかも。(でも、Rubyもやりたいし・・・)&lt;br/&gt;
&lt;br/&gt;
mixiの画像は、ページ表示時にサムネールの一時URLと、画像表示用ページのpermalinkを
返してくれる。画像表示用ページ(show_*_picture.pl)にアクセスすると、これまた画像の一時URLを返してくれる。&lt;br/&gt;
これは、前にmixiからの画像流出騒ぎ(マイミクにしか公開していない日記の写真が、他のメンバに見えてしまう)のときに取られた対応からこうなってるんだけど、こんな面倒なことしなくても画像を返すURLを*.plにして毎回権限チェックをすれば良いんじゃないかと思うんだけど、それだとサーバ負荷が問題になるんだろうか。&lt;br/&gt;
とにかく、一時URLを使われてしまうと、plaggerがcrawlした時間とfastladderで閲覧する時間に開きがあると画像が見えない。&lt;br/&gt;
そこで、日記やトピックの画像があったら画像表示用ページにアクセスして画像をローカルに保存しようと言うわけ。&lt;br/&gt;
&lt;br/&gt;
そのために、まずは、WWW::Mixi::Scraper。こいつは、urlを渡すとscrapingしてハッシュ?を返してくれる。&lt;br/&gt;
Pluginを追加して、画像表示ページにアクセスしたら画像そのものを取ってくるようにする。&lt;br/&gt;
日記の場合は、http://mixi.jp/show_diary_picture.plと言うURLになるので、それ用のPluginを作る。
&lt;pre class="prettyprint"&gt;
package WWW::Mixi::Scraper::Plugin::ShowDiaryPicture;

use strict;
use warnings;
use WWW::Mixi::Scraper::Plugin;

validator {qw(
  id        is_number
  owner_id  is_number
  number    is_number
)};

sub scrape {
  my ($self, $html) = @_;

  $scraper = scraper {
    process 'img',
      link =&gt; '@SRC';
    result qw ( link nil );
  };

  my $stash = $self-&gt;post_process($scraper-&gt;scrape(\$html))-&gt;[0];
  if ($stash-&gt;{link}) {
      $stash-&gt;{image} = $self-&gt;{mech}-&gt;get_content($stash-&gt;{link});
  }
  return $stash;
}

1;

__END__
&lt;/pre&gt;
Pluginの作り方は、Plugin.pmに書いてある。qw がなんだかわからなかった(調べろ→自分)んだけど、post_process() は配列を求めているのに、qw の中身が一つだと配列にならないらしくて怒られたので、ダミーを入れてみた。&lt;br/&gt;
同じように、コミュニティのトピックとトピックコメント用のPluginも作る。
&lt;pre class="prettyprint"&gt;
package WWW::Mixi::Scraper::Plugin::ShowBbsPicture;

use strict;
use warnings;
use WWW::Mixi::Scraper::Plugin;

validator {qw(
  id        is_number
  comm_id  is_number
  number    is_number
)};

sub scrape {
  my ($self, $html) = @_;

  $scraper = scraper {
    process 'img',
      link =&gt; '@SRC';
    result qw ( link nil );
  };

  my $stash = $self-&gt;post_process($scraper-&gt;scrape(\$html))-&gt;[0];
  if ($stash-&gt;{link}) {
      $stash-&gt;{image} = $self-&gt;{mech}-&gt;get_content($stash-&gt;{link});
  }
  return $stash;
}

1;

__END__
&lt;/pre&gt;
&lt;pre class="prettyprint"&gt;
package WWW::Mixi::Scraper::Plugin::ShowBbsCommentPicture;

use strict;
use warnings;
use WWW::Mixi::Scraper::Plugin;

validator {qw(
  id       is_number
  bbs_id   is_number
  comm_id  is_number
  number   is_number
)};

sub scrape {
  my ($self, $html) = @_;

  $scraper = scraper {
    process 'img',
      link =&gt; '@SRC';
    result qw ( link nil );
  };

  my $stash = $self-&gt;post_process($scraper-&gt;scrape(\$html))-&gt;[0];
  if ($stash-&gt;{link}) {
      $stash-&gt;{image} = $self-&gt;{mech}-&gt;get_content($stash-&gt;{link});
  }
  return $stash;
}

1;

__END__
&lt;/pre&gt;
validator のところ(getパラメータ)以外はまったく同じなので、もうちょっとなんとかしたいところだけど、perlのこの辺の仕組みがわからないのでなんともならなかった。&lt;br/&gt;
余談だけど、Scraper.pmのnewを見ると、上記Pluginを書くだけで
&lt;pre class="prettyprint"&gt;
my $pic = $mixi-&gt;parse("/show_diary_picture.pl?owner_id=$oid&amp;amp;id=$id&amp;amp;number=$number");
my $pic = $mixi-&gt;show_diary_picture-&gt;parse( owner_id =&gt; $oid, id =&gt; $id, number =&gt; $number );
&lt;/pre&gt;
のいずれの書き方でも同じ動作をする理由がわかる。こう言うのがさらっと書けるようになると楽しいんだろうな。&lt;br/&gt;
これで、画像を取ってくる下準備はできたので、次はCustomFeed::MixiScraper。&lt;br/&gt;
あまりにやっつけで公開したくないんだけど、まあ参考程度に。&lt;br/&gt;
長いので、全文ではなくhttp://svn.bulknews.net/repos/plagger/trunk/ との差分で。差分を取ったときのリビジョンは2063。(たぶん、ベースにしたバージョンがもっと古いので、最新のものより機能足りないっぽい。最新取り直してやり直した方が良いかなあ。)&lt;br/&gt;
&lt;pre class="prettyprint"&gt;
Index: MixiScraper.pm
===================================================================
--- MixiScraper.pm	(リビジョン 2063)
+++ MixiScraper.pm	(作業コピー)
@@ -74,7 +74,6 @@
       email =&amp;gt; $self-&amp;gt;conf-&amp;gt;{email},
       password =&amp;gt; $self-&amp;gt;conf-&amp;gt;{password},
       cookie_jar =&amp;gt; $cookie_jar,
-      mode =&amp;gt; $self-&amp;gt;conf-&amp;gt;{mode},
     );
 
     my $feed = Plagger::Feed-&amp;gt;new;
@@ -86,15 +85,13 @@
     my($self, $context, $args) = @_;
     for my $type (@{$self-&amp;gt;conf-&amp;gt;{feed_type} || ['FriendDiary']}) {
         $context-&amp;gt;error("$type not found") unless $MAP-&amp;gt;{$type};
-        if ($type eq 'BBS' and $self-&amp;gt;conf-&amp;gt;{split_bbs_feed}) {
-            $self-&amp;gt;aggregate_bbs_feed($context, $type, $args);
-        }
-        else {
-            $self-&amp;gt;aggregate_feed($context, $type, $args);
-        }
+	if ($type eq 'BBS') {
+	    $self-&amp;gt;aggregate_feed_bbs($context, $type, $args);
+	} else {
+	    $self-&amp;gt;aggregate_feed($context, $type, $args);
+	}
     }
 }
-
 sub aggregate_feed {
     my($self, $context, $type, $args) = @_;
 
@@ -102,6 +99,8 @@
     $feed-&amp;gt;type('mixi');
     $feed-&amp;gt;title($MAP-&amp;gt;{$type}-&amp;gt;{title});
 
+    my $format = DateTime::Format::Strptime-&amp;gt;new(pattern =&amp;gt; '%Y-%m-%d %H:%M');
+
     my $meth = $MAP-&amp;gt;{$type}-&amp;gt;{get_list};
     my @msgs = $self-&amp;gt;{mixi}-&amp;gt;$meth-&amp;gt;parse;
     my $items = $self-&amp;gt;conf-&amp;gt;{fetch_items} || 20;
@@ -110,148 +109,274 @@
     $feed-&amp;gt;link($self-&amp;gt;{mixi}-&amp;gt;{mech}-&amp;gt;uri);
 
     my $i = 0;
-    $self-&amp;gt;{blocked} = 0;
+    my $blocked = 0;
     for my $msg (@msgs) {
         next if $type eq 'FriendDiary' and $msg-&amp;gt;{link}-&amp;gt;query_param('url'); # external blog
         last if $i++ &amp;gt;= $items;
 
-        $self-&amp;gt;add_entry( $context, $type, $feed, $msg );
+        my $entry = Plagger::Entry-&amp;gt;new;
+        $entry-&amp;gt;title($msg-&amp;gt;{subject});
+        $entry-&amp;gt;link($msg-&amp;gt;{link});
+        $entry-&amp;gt;author($msg-&amp;gt;{name});
+        $entry-&amp;gt;date( Plagger::Date-&amp;gt;parse($format, $msg-&amp;gt;{time}) );
+	if ($entry-&amp;gt;date) {
+	    $entry-&amp;gt;date-&amp;gt;set_time_zone('Asia/Tokyo');
+	}
+        if ($self-&amp;gt;conf-&amp;gt;{show_icon} &amp;amp;&amp;amp; !$blocked &amp;amp;&amp;amp; defined $MAP-&amp;gt;{$type}-&amp;gt;{icon}) {
+            my $owner_id = $msg-&amp;gt;{link}-&amp;gt;query_param($MAP-&amp;gt;{$type}-&amp;gt;{icon});
+            $context-&amp;gt;log(info =&amp;gt; "Fetch icon of id=$owner_id");
+
+            my $item = $self-&amp;gt;cache-&amp;gt;get_callback(
+                "outline-$owner_id",
+                sub {
+                    Time::HiRes::sleep( $self-&amp;gt;conf-&amp;gt;{fetch_body_interval} || 1.5 );
+                    my $item = $self-&amp;gt;{mixi}-&amp;gt;show_friend-&amp;gt;parse(id =&amp;gt; $owner_id)-&amp;gt;{outline};
+                    $item;
+                },
+                '12 hours',
+            );
+            if ($item &amp;amp;&amp;amp; $item-&amp;gt;{image} !~ /no_photo/) {
+                # prefer smaller image
+                my $image = $item-&amp;gt;{image};
+                   $image =~ s/\.jpg$/s.jpg/;
+                $entry-&amp;gt;icon({
+                    title =&amp;gt; $item-&amp;gt;{name},
+                    url   =&amp;gt; $image,
+                    link  =&amp;gt; $item-&amp;gt;{link},
+                });
+            }
+        }
+
+        my @comments;
+        if ($self-&amp;gt;conf-&amp;gt;{fetch_body} &amp;amp;&amp;amp; !$blocked &amp;amp;&amp;amp; $msg-&amp;gt;{link} =~ /view_/ &amp;amp;&amp;amp; defined $MAP-&amp;gt;{$type}-&amp;gt;{get_detail}) {
+            # view_enquete is not implemented and probably
+            # won't be implemented as it seems redirected to
+            # reply_enquete
+            next if $msg-&amp;gt;{link} =~ /view_enquete/;
+            $context-&amp;gt;log(info =&amp;gt; "Fetch body from $msg-&amp;gt;{link}");
+            my $item = $self-&amp;gt;cache-&amp;gt;get_callback(
+                "item-".$msg-&amp;gt;{link},
+                sub {
+                    Time::HiRes::sleep( $self-&amp;gt;conf-&amp;gt;{fetch_body_interval} || 1.5 );
+                    my $item = $self-&amp;gt;{mixi}-&amp;gt;parse($msg-&amp;gt;{link});
+                    $item;
+                },
+                '12 hours',
+            );
+            if ($item) {
+                my $body = $item-&amp;gt;{description};
+                   $body =~ s!(\r\n?|\n)!&amp;lt;br /&amp;gt;!g;
+                for my $image (@{ $item-&amp;gt;{images} || [] }) {
+		    my $imagelink = $image-&amp;gt;{link};
+		    $imagelink =~ s!.*(show_.*?_picture\.pl.*?)'.*!http://mixi.jp/$1!;
+		    if ( $self-&amp;gt;conf-&amp;gt;{fetch_image} ) {
+			my $pic = $self-&amp;gt;{mixi}-&amp;gt;parse($imagelink);
+			if ($pic-&amp;gt;{image}) {
+			    my $filename = $pic-&amp;gt;{link};
+			    $filename =~ s!.*/!!;
+			    open(OUT, "&amp;gt;" . $self-&amp;gt;conf-&amp;gt;{fetch_image_path} . "/images/mixi/diary/" . $filename);
+			    print OUT $pic-&amp;gt;{image};
+			    close(OUT);
+			    my $imagepath = "/images/mixi/diary/$filename";
+			    $body .= qq(&amp;lt;a href="$imagelink"&amp;gt;&amp;lt;img src="$imagepath" /&amp;gt;&amp;lt;/a&amp;gt;);
+			} else {
+			    $body .= qq(&amp;lt;a href="$imagelink"&amp;gt;&amp;lt;object type="text/html" data="$imagelink" &amp;gt;$imagelink&amp;lt;/object&amp;gt;&amp;lt;/a&amp;gt;);
+			}
+		    } else {
+			$body .= qq(&amp;lt;a href="$imagelink"&amp;gt;&amp;lt;object type="text/html" data="$imagelink" &amp;gt;$imagelink&amp;lt;/object&amp;gt;&amp;lt;/a&amp;gt;);
+		    }
+                }
+                $entry-&amp;gt;body($body);
+
+                $entry-&amp;gt;date( Plagger::Date-&amp;gt;parse($format, $item-&amp;gt;{time}) );
+		if ($entry-&amp;gt;date) {
+		    $entry-&amp;gt;date-&amp;gt;set_time_zone('Asia/Tokyo');
+		}
+                if ($self-&amp;gt;conf-&amp;gt;{fetch_comment}) {
+                  for my $comment (@{ $item-&amp;gt;{comments} || [] }) {
+                      my $c = Plagger::Entry-&amp;gt;new;
+                         $c-&amp;gt;title($entry-&amp;gt;title . ': '. $comment-&amp;gt;{subject});
+                         $c-&amp;gt;body($comment-&amp;gt;{description});
+                         $c-&amp;gt;link($comment-&amp;gt;{link});
+                         $c-&amp;gt;author($comment-&amp;gt;{name});
+                         $c-&amp;gt;date( Plagger::Date-&amp;gt;parse($format, $comment-&amp;gt;{time}) );
+		      if ($c-&amp;gt;date) {
+			  $c-&amp;gt;date-&amp;gt;set_time_zone('Asia/Tokyo');
+		      }
+                      push @comments, $c;
+                  }
+                }
+            } else {
+                $context-&amp;gt;log(warn =&amp;gt; "Fetch body failed. You might be blocked?");
+                $blocked++;
+            }
+        }
+
+        $feed-&amp;gt;add_entry($entry);
+        for my $comment ( @comments ) {
+            $feed-&amp;gt;add_entry($comment);
+        }
     }
 
     $context-&amp;gt;update-&amp;gt;add($feed);
 }
 
-sub aggregate_bbs_feed {
+sub aggregate_feed_bbs {
     my($self, $context, $type, $args) = @_;
 
+
+    my $format = DateTime::Format::Strptime-&amp;gt;new(pattern =&amp;gt; '%Y-%m-%d %H:%M');
+
     my $meth = $MAP-&amp;gt;{$type}-&amp;gt;{get_list};
     my @msgs = $self-&amp;gt;{mixi}-&amp;gt;$meth-&amp;gt;parse;
     my $items = $self-&amp;gt;conf-&amp;gt;{fetch_items} || 20;
     $self-&amp;gt;log(info =&amp;gt; 'fetch ' . scalar(@msgs) . ' entries');
 
+
     my $i = 0;
-    $self-&amp;gt;{blocked} = 0;
+    my $blocked = 0;
     for my $msg (@msgs) {
-        next if $type eq 'FriendDiary' and $msg-&amp;gt;{link}-&amp;gt;query_param('url'); # external blog
         last if $i++ &amp;gt;= $items;
 
-        my $feed = Plagger::Feed-&amp;gt;new;
-        $feed-&amp;gt;type('mixi');
-        (my $subject = $msg-&amp;gt;{subject}) =~ s/\(\d+\)$//;
-        (my $link = $msg-&amp;gt;{link}) =~ s/&amp;amp;comment_count=\d*//;
-        $feed-&amp;gt;title($subject);
-        $feed-&amp;gt;description($MAP-&amp;gt;{$type}-&amp;gt;{title}.': '.$msg-&amp;gt;{name});
-        $feed-&amp;gt;link($link);
+	my $feed = Plagger::Feed-&amp;gt;new;
+	$feed-&amp;gt;type('mixi');
+	my $subject = $msg-&amp;gt;{subject};
+	$subject =~ s/\([0-9]*\)$//;
+	$feed-&amp;gt;title($subject);
+	$feed-&amp;gt;description('Mixi: ' . $msg-&amp;gt;{name});
+	my $link = $msg-&amp;gt;{link};
+	$link =~ s/&amp;amp;comment_count=[0-9]*//;
+	$feed-&amp;gt;link($link);
 
-        $self-&amp;gt;add_entry( $context, $type, $feed, $msg );
+        my $entry = Plagger::Entry-&amp;gt;new;
+        $entry-&amp;gt;title($subject);
+        $entry-&amp;gt;link($link);
+        $entry-&amp;gt;author($msg-&amp;gt;{name});
+        $entry-&amp;gt;date( Plagger::Date-&amp;gt;parse($format, $msg-&amp;gt;{time}) );
+	if ($entry-&amp;gt;date) {
+	    $entry-&amp;gt;date-&amp;gt;set_time_zone('Asia/Tokyo');
+	}
+        if ($self-&amp;gt;conf-&amp;gt;{show_icon} &amp;amp;&amp;amp; !$blocked &amp;amp;&amp;amp; defined $MAP-&amp;gt;{$type}-&amp;gt;{icon}) {
+            my $owner_id = $msg-&amp;gt;{link}-&amp;gt;query_param($MAP-&amp;gt;{$type}-&amp;gt;{icon});
+            $context-&amp;gt;log(info =&amp;gt; "Fetch icon of id=$owner_id");
 
-        $context-&amp;gt;update-&amp;gt;add($feed);
-    }
-}
-
-my $format = DateTime::Format::Strptime-&amp;gt;new(pattern =&amp;gt; '%Y-%m-%d %H:%M');
-
-sub parse_date {
-    my ($self, $datetime) = @_;
-
-    # Calendar doesn't have %H:%M part (spotted by id:mad-capone)
-    return unless defined $datetime;
-    $datetime .= ' 00:00' unless $datetime =~ /\d+:\d+$/;
-
-    Plagger::Date-&amp;gt;parse($format, $datetime);
-}
-
-sub add_entry {
-    my ($self, $context, $type, $feed, $msg) = @_;
-
-    if ($type eq 'Log') {
-        $msg-&amp;gt;{subject} = $msg-&amp;gt;{time} . ' ' . $msg-&amp;gt;{name};
-    }
-
-    my $entry = Plagger::Entry-&amp;gt;new;
-    $entry-&amp;gt;title($msg-&amp;gt;{subject});
-    $entry-&amp;gt;link($msg-&amp;gt;{link});
-    $entry-&amp;gt;author($msg-&amp;gt;{name});
-    $entry-&amp;gt;date( $self-&amp;gt;parse_date($msg-&amp;gt;{time}) );
-    $entry-&amp;gt;date-&amp;gt;set_time_zone('Asia/Tokyo') if $entry-&amp;gt;date;
-
-    if ($self-&amp;gt;conf-&amp;gt;{show_icon} &amp;amp;&amp;amp; !$self-&amp;gt;{blocked} &amp;amp;&amp;amp; defined $MAP-&amp;gt;{$type}-&amp;gt;{icon}) {
-        my $owner_id = $msg-&amp;gt;{link}-&amp;gt;query_param($MAP-&amp;gt;{$type}-&amp;gt;{icon});
-        $context-&amp;gt;log(info =&amp;gt; "Fetch icon of id=$owner_id");
-
-        my $item = $self-&amp;gt;cache-&amp;gt;get_callback(
-            "outline-$owner_id",
-            sub {
-                Time::HiRes::sleep( $self-&amp;gt;conf-&amp;gt;{fetch_body_interval} || 1.5 );
-                my $item = $self-&amp;gt;{mixi}-&amp;gt;show_friend-&amp;gt;parse(id =&amp;gt; $owner_id)-&amp;gt;{outline};
-                $item;
-            },
-            '12 hours',
-        );
-        if ($item &amp;amp;&amp;amp; $item-&amp;gt;{image} !~ /no_photo/) {
-            # prefer smaller image
-            my $image = $item-&amp;gt;{image};
-               $image =~ s/\.jpg$/s.jpg/;
-            $entry-&amp;gt;icon({
-                title =&amp;gt; $item-&amp;gt;{name},
-                url   =&amp;gt; $image,
-                link  =&amp;gt; $item-&amp;gt;{link},
-            });
+            my $item = $self-&amp;gt;cache-&amp;gt;get_callback(
+                "outline-$owner_id",
+                sub {
+                    Time::HiRes::sleep( $self-&amp;gt;conf-&amp;gt;{fetch_body_interval} || 1.5 );
+                    my $item = $self-&amp;gt;{mixi}-&amp;gt;show_friend-&amp;gt;parse(id =&amp;gt; $owner_id)-&amp;gt;{outline};
+                    $item;
+                },
+                '12 hours',
+            );
+            if ($item &amp;amp;&amp;amp; $item-&amp;gt;{image} !~ /no_photo/) {
+                # prefer smaller image
+                my $image = $item-&amp;gt;{image};
+                   $image =~ s/\.jpg$/s.jpg/;
+                $entry-&amp;gt;icon({
+                    title =&amp;gt; $item-&amp;gt;{name},
+                    url   =&amp;gt; $image,
+                    link  =&amp;gt; $item-&amp;gt;{link},
+                });
+            }
         }
-    }
 
-    my @comments;
-    if ($self-&amp;gt;conf-&amp;gt;{fetch_body} &amp;amp;&amp;amp; !$self-&amp;gt;{blocked} &amp;amp;&amp;amp; $msg-&amp;gt;{link} =~ /view_/ &amp;amp;&amp;amp; defined $MAP-&amp;gt;{$type}-&amp;gt;{get_detail}) {
-        # view_enquete is not implemented and probably
-        # won't be implemented as it seems redirected to
-        # reply_enquete
-        return if $msg-&amp;gt;{link} =~ /view_enquete/;
-        $context-&amp;gt;log(info =&amp;gt; "Fetch body from $msg-&amp;gt;{link}");
-        my $item = $self-&amp;gt;cache-&amp;gt;get_callback(
-            "item-".$msg-&amp;gt;{link},
-            sub {
-                Time::HiRes::sleep( $self-&amp;gt;conf-&amp;gt;{fetch_body_interval} || 1.5 );
-                my $item = $self-&amp;gt;{mixi}-&amp;gt;parse($msg-&amp;gt;{link});
-                $item;
-            },
-            '12 hours',
-        );
-        if ($item) {
-            my $body = $item-&amp;gt;{description};
-               $body =~ s!(\r\n?|\n)!&amp;lt;br /&amp;gt;!g;
-            for my $image (@{ $item-&amp;gt;{images} || [] }) {
-                $body .= qq(&amp;lt;div&amp;gt;&amp;lt;a href="$image-&amp;gt;{link}"&amp;gt;&amp;lt;img src="$image-&amp;gt;{thumb_link}" style="border:0" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;);
-                my $enclosure = Plagger::Enclosure-&amp;gt;new;
-                $enclosure-&amp;gt;url($image-&amp;gt;{thumb_link});
-                $enclosure-&amp;gt;auto_set_type;
-                $enclosure-&amp;gt;is_inline(1);
-                $entry-&amp;gt;add_enclosure($enclosure);
-            }
-            $entry-&amp;gt;body($body);
+        my @comments;
+        if ($self-&amp;gt;conf-&amp;gt;{fetch_body} &amp;amp;&amp;amp; !$blocked &amp;amp;&amp;amp; $msg-&amp;gt;{link} =~ /view_/ &amp;amp;&amp;amp; defined $MAP-&amp;gt;{$type}-&amp;gt;{get_detail}) {
+            # view_enquete is not implemented and probably
+            # won't be implemented as it seems redirected to
+            # reply_enquete
+            next if $msg-&amp;gt;{link} =~ /view_enquete/;
+            $context-&amp;gt;log(info =&amp;gt; "Fetch body from $msg-&amp;gt;{link}");
+            my $item = $self-&amp;gt;cache-&amp;gt;get_callback(
+                "item-".$msg-&amp;gt;{link},
+                sub {
+                    Time::HiRes::sleep( $self-&amp;gt;conf-&amp;gt;{fetch_body_interval} || 1.5 );
+                    my $item = $self-&amp;gt;{mixi}-&amp;gt;parse($msg-&amp;gt;{link});
+                    $item;
+                },
+                '12 hours',
+            );
+            if ($item) {
+                my $body = $item-&amp;gt;{description};
+                   $body =~ s!(\r\n?|\n)!&amp;lt;br /&amp;gt;!g;
+		if ( $self-&amp;gt;conf-&amp;gt;{fetch_image} ) {
+		    while ($body =~ /&amp;lt;a href=.*?&amp;amp;#39;(.*?)&amp;amp;#39;.*?&amp;lt;\/a&amp;gt;/) {
+			   my $imagelink = "http://mixi.jp/" . $1;
+			      $imagelink =~ s!&amp;amp;#38;!&amp;amp;!g;
+			   my $pic = $self-&amp;gt;{mixi}-&amp;gt;parse($imagelink);
+			   if ($pic-&amp;gt;{image}) {
+			       my $filename = $pic-&amp;gt;{link};
+			       $filename =~ s!.*/!!;
+			       open(OUT, "&amp;gt;" . $self-&amp;gt;conf-&amp;gt;{fetch_image_path} . "/images/mixi/bbs/" . $filename);
+			       print OUT $pic-&amp;gt;{image};
+			       close(OUT);
+			       my $imagepath = "/images/mixi/bbs/$filename";
+			       $body =~ s!&amp;lt;a href=.*?&amp;amp;#39;.*?&amp;amp;#39;.*?&amp;lt;/a&amp;gt;!&amp;lt;a href="$imagelink"&amp;gt;&amp;lt;img src="$imagepath"/&amp;gt;&amp;lt;/a&amp;gt;!;
+			   } else {
+			       $body =~ s!&amp;lt;a href=.*?&amp;amp;#39;(.*?)&amp;amp;#39;.*?&amp;lt;/a&amp;gt;!&amp;lt;object type="text/html" data="http://mixi.jp/$1"&amp;gt;http://mixi.jp/$1&amp;lt;/object&amp;gt;!;
+			   }
+		    }
+		} else {
+		    $body =~ s!&amp;lt;a href=.*?&amp;amp;#39;(.*?)&amp;amp;#39;.*?&amp;lt;/a&amp;gt;!&amp;lt;object type="text/html" data="http://mixi.jp/$1"&amp;gt;http://mixi.jp/$1&amp;lt;/object&amp;gt;!g;
+		}
+		$body =~ s!&amp;amp;#38;!&amp;amp;!g;
+                $entry-&amp;gt;body($body);
 
-            $entry-&amp;gt;date( $self-&amp;gt;parse_date($item-&amp;gt;{time}) );
-            $entry-&amp;gt;date-&amp;gt;set_time_zone('Asia/Tokyo') if $entry-&amp;gt;date;
-            if ($self-&amp;gt;conf-&amp;gt;{fetch_comment}) {
-              for my $comment (@{ $item-&amp;gt;{comments} || [] }) {
-                  my $c = Plagger::Entry-&amp;gt;new;
-                     $c-&amp;gt;title($entry-&amp;gt;title . ': '. $comment-&amp;gt;{subject});
-                     $c-&amp;gt;body($comment-&amp;gt;{description});
-                     $c-&amp;gt;link($comment-&amp;gt;{link});
-                     $c-&amp;gt;author($comment-&amp;gt;{name});
-                     $c-&amp;gt;date( $self-&amp;gt;parse_date($comment-&amp;gt;{time}) );
-                     $c-&amp;gt;date-&amp;gt;set_time_zone('Asia/Tokyo') if $c-&amp;gt;date;
-                  push @comments, $c;
-              }
+                $entry-&amp;gt;date( Plagger::Date-&amp;gt;parse($format, $item-&amp;gt;{time}) );
+		if ($entry-&amp;gt;date) {
+		    $entry-&amp;gt;date-&amp;gt;set_time_zone('Asia/Tokyo');
+		}
+                if ($self-&amp;gt;conf-&amp;gt;{fetch_comment}) {
+                  for my $comment (@{ $item-&amp;gt;{comments} || [] }) {
+                      my $c = Plagger::Entry-&amp;gt;new;
+                         $c-&amp;gt;title($subject . ': '. $comment-&amp;gt;{subject});
+		      $body = $comment-&amp;gt;{description};
+		      if ( $self-&amp;gt;conf-&amp;gt;{fetch_image} ) {
+			  while ($body =~ /&amp;lt;a href=.*?&amp;amp;#39;(.*?)&amp;amp;#39;.*?&amp;lt;\/a&amp;gt;/) {
+			      my $imagelink = "http://mixi.jp/" . $1;
+			      $imagelink =~ s!&amp;amp;#38;!&amp;amp;!g;
+			      my $pic = $self-&amp;gt;{mixi}-&amp;gt;parse($imagelink);
+			      if ($pic-&amp;gt;{image}) {
+				  my $filename = $pic-&amp;gt;{link};
+				  $filename =~ s!.*/!!;
+				  open(OUT, "&amp;gt;" . $self-&amp;gt;conf-&amp;gt;{fetch_image_path} . "/images/mixi/bbs/" . $filename);
+				  print OUT $pic-&amp;gt;{image};
+				  close(OUT);
+				  my $imagepath = "/images/mixi/bbs/$filename";
+				  $body =~ s!&amp;lt;a href=.*?&amp;amp;#39;.*?&amp;amp;#39;.*?&amp;lt;/a&amp;gt;!&amp;lt;a href="$imagelink"&amp;gt;&amp;lt;img src="$imagepath"/&amp;gt;&amp;lt;/a&amp;gt;!;
+			      } else {
+				  $self-&amp;gt;log(debug =&amp;gt; "bbs_comment_picture $1 something wrong");
+				  $body =~ s!&amp;lt;a href=.*?&amp;amp;#39;(.*?)&amp;amp;#39;.*?&amp;lt;/a&amp;gt;!&amp;lt;object type="text/html" data="http://mixi.jp/$1"&amp;gt;http://mixi.jp/$1&amp;lt;/object&amp;gt;!;
+			      }
+			  }
+		      } else {
+			  $body =~ s!&amp;lt;a href=.*?&amp;amp;#39;(.*?)&amp;amp;#39;.*?&amp;lt;/a&amp;gt;!&amp;lt;object type="text/html" data="http://mixi.jp/$1"&amp;gt;http://mixi.jp/$1&amp;lt;/object&amp;gt;!g;
+		      }
+		      $body =~ s!&amp;amp;#38;!&amp;amp;!g;
+                         $c-&amp;gt;body($body);
+		      $link = $comment-&amp;gt;{link};
+		      $link =~ s/&amp;amp;comment_count=[0-9]*//;
+                         $c-&amp;gt;link($link);
+                         $c-&amp;gt;author($comment-&amp;gt;{name});
+                         $c-&amp;gt;date( Plagger::Date-&amp;gt;parse($format, $comment-&amp;gt;{time}) );
+		      if ($c-&amp;gt;date) {
+			  $c-&amp;gt;date-&amp;gt;set_time_zone('Asia/Tokyo');
+		      }
+                      push @comments, $c;
+                  }
+                }
+            } else {
+                $context-&amp;gt;log(warn =&amp;gt; "Fetch body failed. You might be blocked?");
+                $blocked++;
             }
-        } else {
-            $context-&amp;gt;log(warn =&amp;gt; "Fetch body failed. You might be blocked?");
-            $self-&amp;gt;{blocked}++;
         }
-    }
 
-    $feed-&amp;gt;add_entry($entry);
-    for my $comment ( @comments ) {
-        $feed-&amp;gt;add_entry($comment);
+        $feed-&amp;gt;add_entry($entry);
+        for my $comment ( @comments ) {
+            $feed-&amp;gt;add_entry($comment);
+        }
+	$context-&amp;gt;update-&amp;gt;add($feed);
     }
 }
 
@@ -320,10 +445,6 @@
 With this option set, this plugin fetches users buddy icon from
 mixi.jp site, which makes the output HTML very user-friendly.
 
-=item split_bbs_feed
-
-With this option set, BBS feed will be split up. Defaults to 0.
-
 =item feed_type
 
 With this option set, you can set the feed types.
&lt;/pre&gt;
これで、plaggerのyamlのMixiScraperのところに
&lt;pre class="textfile"&gt;
    config:
      fetch_image: 1
      fetch_image_path: /var/www/fastladder/public
 &lt;/pre&gt;
とか書くと、$fetch_image_path/images/mixi に画像が保存される。&lt;br/&gt;
本来は、CustomFeed::MixiScraperの段階では Plagger::Entry に Plagger::Enclosureを入れておいて、Store::Fastladder でファイル出力した方が正しい(gmailとかにも添付で送れるはずだし)と思うんだけど、あくまでやっつけなので。(言い訳ばっかりだな)</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/t960MrI_F5o/003898.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003898.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Plagger</category>
            
            
            <pubDate>Fri, 11 Sep 2009 09:58:05 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003898.html</feedburner:origLink></item>
        
        <item>
            <title>fastladder を Passenger で</title>
            <description>今まで mongrel を使って、Apache の mod_proxy でやっていたのですが、Redmine をインストールするときに知った Passenger を使ってみることにしました。&lt;br/&gt;
会社マシンに Passenger を入れたときにはいろいろモジュールが足りなくて何度もインストーラに怒られたのですが、自宅マシンだと一発で入りました。&lt;br/&gt;
あまりに簡単で記事にするほどでもないのですが、備忘録に。
&lt;pre class="commandline"&gt;
# gem install passenger
Building native extensions.  This could take a while...
Successfully installed passenger-2.2.5
1 gem installed
Installing ri documentation for passenger-2.2.5...
Installing RDoc documentation for passenger-2.2.5...
# passenger-install-apache2-module
Welcome to the Phusion Passenger Apache 2 module installer, v2.2.5.

This installer will guide you through the entire installation process. It
shouldn't take more than 3 minutes in total.

Here's what you can expect from the installation process:

 1. The Apache 2 module will be installed for you.
 2. You'll learn how to configure Apache.
 3. You'll learn how to deploy a Ruby on Rails application.

Don't worry if anything goes wrong. This installer will advise you on how to
solve any problems.

Press Enter to continue, or Ctrl-C to abort.


--------------------------------------------

Checking for required software...

 * GNU C++ compiler... found at /usr/bin/g++
 * Ruby development headers... found
 * OpenSSL support for Ruby... found
 * RubyGems... found
 * Rake... found at /usr/local/bin/rake
 * Apache 2... found at /usr/local/sbin/httpd
 * Apache 2 development headers... found at /usr/local/sbin/apxs
 * Apache Portable Runtime (APR) development headers... found at /usr/local/bin/apr-1-config
 * Apache Portable Runtime Utility (APU) development headers... found at /usr/local/bin/apu-1-config

--------------------------------------------
(・・mod_passengerのコンパイル＆インストール・・)
--------------------------------------------
The Apache 2 module was successfully installed.

Please edit your Apache configuration file, and add these lines:

   LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.5/ext/apache2/mod_passenger.so
   PassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.5
   PassengerRuby /usr/local/bin/ruby18

After you restart Apache, you are ready to deploy any number of Ruby on Rails
applications on Apache, without any further Ruby on Rails-specific
configuration!

Press ENTER to continue.


--------------------------------------------
Deploying a Ruby on Rails application: an example

Suppose you have a Ruby on Rails application in /somewhere. Add a virtual host
to your Apache configuration file, and set its DocumentRoot to
/somewhere/public, like this:

   &lt;VirtualHost *:80&gt;
      ServerName www.yourhost.com
      DocumentRoot /somewhere/public    # &lt;-- be sure to point to 'public'!
   &lt;/VirtualHost&gt;

And that's it! You may also want to check the Users Guide for security and
optimization tips and other useful information:

  /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.5/doc/Users guide Apache.html

Enjoy Phusion Passenger, a product of Phusion (www.phusion.nl) :-)
http://www.modrails.com/

Phusion Passenger is a trademark of Hongli Lai &amp; Ninh Bui.
&lt;/pre&gt;
後は、passenger-install-apache2-module に表示されたとおりに apacheの設定ファイルを変えるだけ。&lt;br/&gt;
もともと mongrel に飛ばす設定が書いてあったので、LoadModule からの3行の追加とProxyPass* の行を消すだけであっけなく動きました。&lt;br/&gt;
後は、mongrelを止めて終わりです。&lt;br/&gt;
Railsアプリをちょっといじったときは、$RAILS_ROOT/tmp/restart.txt と言うファイルを作成すればそのアプリだけ再起動してくれるそうです。</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/6otJKJ1aIyE/003896.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003896.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Ruby</category>
            
            
            <pubDate>Thu, 10 Sep 2009 09:37:56 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003896.html</feedburner:origLink></item>
        
        <item>
            <title>fastladder を PostgreSQLで動かす</title>
            <description>最近open fastladderがやけに遅い。&lt;br/&gt;
MySQLのチューニングなんかを見て、少しmy.cnfをいじってみたりしたけど効果なし。&lt;br/&gt;
itemsテーブルから古い記事を消すと少しだけ効果があるかな？と言う感じ。&lt;br/&gt;
そもそもMySQLは慣れていないので、古い記事を消すとかでも苦労しちゃう。&lt;br/&gt;
で、RrailsのActiveRecord?はPostgreSQLに対応しているんじゃないかと思って調べて見たら、いけそうな雰囲気。&lt;br/&gt;
まずは、fastladder/config/database.yml を修正。&lt;br/&gt;
&lt;pre class="textfile"&gt;
production:
  adapter: postgresql
  encoding: utf8
  database: fastladder_production
  username: fastladder
  password: &lt;i&gt;password&lt;/i&gt;
  host: localhost
&lt;/pre&gt;
変えたのは、adapterをmysqlからpostgresqlにして、socketをhostに変えただけ。&lt;br/&gt;
pgsqlユーザでDB fastladder_productionとユーザfastladderを作成して、rake db:migrateしてみたら、なんかpostgresがないみたいなエラーが出たので、
&lt;pre class="commandline"&gt;
# gem install postgres
&lt;/pre&gt;
としてpostgresをインストールしたら、無事にrakeでテーブルが作られた。&lt;br/&gt;
あとは、PlaggerのStore::Fastladderなんだけど、こちらも中身を見たら直接SQLなんて書いてなくて、DBIx::Class::Schema::Loader とか言うのを使ってORマッピングしてるっぽい。&lt;br/&gt;
手元の環境を見たら、p5-DBD-Pgと言うのが入っていたので、Plaggerのyamlを修正してみる。
&lt;pre class="textfile"&gt;
  - module: Store::Fastladder
    config:
      connect_info:
        - dbi:Pg:dbname=fastladder_production
        - fastladder
        - &lt;i&gt;password&lt;/i&gt;
      member_id: 1
&lt;/pre&gt;
dbi:mysqlをdbi:Pgに変更して、後は接続パラメータの指定方法が違うのを適当に修正した。&lt;br/&gt;
plaggerを実行してみると、membersにid=1の人なんていないってエラーになるので、MySQLからmembersテーブルだけPostgreSQLに移行。&lt;a href="http://kapi.jp/kapi_blog/217"&gt;MysqlからPostgresへ移行 - かぴぶろぐ&lt;/a&gt;を参考にしたけど、記事の通りだとデータ中の改行が消えてしまうのでsedを使った。&lt;br/&gt;
&lt;ol&gt;
&lt;li&gt;mysqlで実行(DBの管理者ユーザでやる)
&lt;pre class="commandline"&gt;
# mysql -u root fastladder_production -p
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1604
Server version: 5.0.77 FreeBSD port: mysql-server-5.0.77_1

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql&gt; select * from members into outfile '/tmp/members.csv' fields terminated by ',' optionally enclosed by '\"';
Query OK, 1 row affected (0.02 sec)
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;ファイルを覗くと、データ中の改行が\＋改行になっているので、\を削除する。
&lt;pre class="commandline"&gt;
# sed 's/\\$//' &lt; /tmp/members.csv &gt; /tmp/members2.csv
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL側で実行(こちらもDB管理者ユーザで)
&lt;pre class="commandline"&gt;
% psql -U pgsql fastladder_production -W
Password for user pgsql:
Welcome to psql 8.1.17, the PostgreSQL interactive terminal.

Type:  \copyright for distribution terms
       \h for help with SQL commands
       \? for help with psql commands
       \g or terminate with semicolon to execute query
       \q to quit

fastladder_production=# copy members from '/tmp/members2.csv' with csv null as '\\N' escape '\\';
&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
再度plaggerを実行すると、今度はDateTime/Format/Pgがないと怒られたので、portsから devel/p5-DateTime-Format-Pg をインストール。&lt;br/&gt;
今度こそうまくPostgreSQLにデータが入った。&lt;br/&gt;
面倒なので過去のデータはそのまま捨てる(と言うかMySQLに入れたまま)にして、これから先のデータだけPostgreSQLを使うことにする。&lt;br/&gt;
しかし、あっけないほど簡単だった。今回対象にした、fastladderとPlagger::Plugin::Store::Fastladderがそれぞれ特定のDBに依存していなかったおかげだ。&lt;br/&gt;
RubyとかPerlは、普通にORマッピングを使ってるのに対して、Javaだとまだまだ閾が高いような気がするのは何故だろうか。&lt;br/&gt;
&lt;br/&gt;

次は、mongrel捨ててPassengerへの移行だな。</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/w3Hr7XzhI5g/003895.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003895.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Plagger</category>
            
            
            <pubDate>Wed, 09 Sep 2009 23:07:49 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003895.html</feedburner:origLink></item>
        
        <item>
            <title>fastladder の iPhone 用 UI</title>
            <description>RSSリーダとして、オープンソース版のfastladderを使っている。&lt;br/&gt;
fastladder は https のクライアント認証が必要な場所に置いてあって、標準のcrawlerではなくPlagger の Store::Fastladder を使って feed を入力している。&lt;br/&gt;
外出中は主にiPhoneを利用しているのだけれど、iPhoneで自前のクライアント証明書を入れる方法がわからなくて使えなかった。&lt;br/&gt;
今回、久しぶりに検索してみたら、&lt;a href="http://iphone.ipsec.jp/content/2008/07/iphone-3g.html"&gt;iPhone 3Gでユーザー証明書を利用してみる - iPhone用連絡先交換サービス（QR Card）＆ 設定情報等　｜　iPhone Lab.&lt;/a&gt;と言う記事を発見した。&lt;br/&gt;
リンク先を見たら、既に「iPhone Configuration Utility 1.0 for Mac OS X」はリンク切れになっていたけれど、検索したら&lt;a href="http://support.apple.com/downloads/iPhone_Configuration_Utility_2_0_for_Windows"&gt;iPhone Configuration Utility 2.0 for Windows&lt;/a&gt;と言うのを見つけたので、早速ダウンロードして使ってみた。&lt;br/&gt;
iPhone用のクライアント証明書と、オレオレCAの証明書をiPhone Configuration Utilityにimportして、構成ファイルを作成し、iPhoneにメールする。クライアント証明書をimportするときに、「export可能にする」にチェックしないと構成ファイルに秘密鍵を含めることができない。&lt;br/&gt;
iPhone側でメールに添付されたファイルをインストールすると、無事にiPhoneでクライアント証明書が使えるようになった。&lt;br/&gt;
しかし、fastladderはデスクトップPCでキーボードを使って操作することを前提に作られているので、iPhoneでは使い物にならない。&lt;br/&gt;
以前、&lt;a href="http://coderepos.org/share/browser/lang/ruby/fastladder_mobile"&gt;fastladder_mobile&lt;/a&gt;と言うのを入れていたので、それで見てみたらなんとか見れた。&lt;br/&gt;
しかし、cssが適用されないっぽい。どうも、iPhone の Safari はサーバの証明書のホスト名が一致しないと css や javascript を実行してくれないようだ。&lt;br/&gt;
なんでホスト名が一致しないかと言うと、以下の理由による。
&lt;ul&gt;
&lt;li&gt;Apache の名前ベースのVirtualHostは、ホスト名ごとに別のサーバ証明書を扱えない(ので、サーバ証明書の名前はwww.wizard-limit.net)&lt;/li&gt;
&lt;li&gt;fastladder は、コンテキストパスが / でないと実行できないため、メインのWebサーバとは別のホスト名を割り当てている&lt;/li&gt;
&lt;/ul&gt;
しょうがないので、https ではなく http 側も fastladder を有効にして、digest認証をかけてみた。&lt;br/&gt;
これで、iPhoneから見られるようになったのだが、fastladder_mobile にはいくつか気に入らないところが。
&lt;ul&gt;
&lt;li&gt;itemの並び順が、昇順ではなく降順&lt;/li&gt;
&lt;li&gt;設定で1ページの上限件数が指定できるが、一つのfeedに上限件数以上があると、その分は表示されてしまう。&lt;/li&gt;
&lt;/ul&gt;
ソースを少しいじって昇順に並ぶようにして、上限件数で切るようにしてみたが、問題が残った。&lt;br/&gt;
たとえば、あるfeedに未読が200件あったとして、最初の30件を表示させて、次のページに行くと200件全てが既読になってしまうのだ。&lt;br/&gt;
これは、fastladder の未読管理の仕組みに問題がある。&lt;br/&gt;
&lt;ul&gt;
&lt;li&gt;subscriptionsと言うテーブルにviewed_onと言う最後に読んだ日時と、has_unread と言うフラグがある&lt;/li&gt;
&lt;li&gt;items と言うテーブルに stored_onと言う取得日時がある。&lt;/li&gt;
&lt;li&gt;既読にする処理は、subscriptionsのviewed_onを現在日時にして、has_unread を false にすると言う処理のため、全てが既読になってしまう&lt;/li&gt;
&lt;/ul&gt;
デスクトップのUIでは、When to mark a feed as read と言う設定がImmediately after loading.となっていればほぼ問題は起きないが、それ以外の設定だと問題が置きそうだ。&lt;br/&gt;
iPhoneや携帯では、1ページあたりの件数はある程度の数に限定したい。&lt;br/&gt;
そこで、今までRailsがわからないからと避けていたのだけれど、iPhone用になんとかしてみることにした。&lt;br/&gt;
iPhone対応にすると言うことで、iuiとかiWebKitとか試してみたんだけど、どちらもあまり気に入らなかった(iuiはアニメーションが遅かった、iWebKitはチェックボックスがimageを使ったトグルボタンになってしまう)のでiWebKitをベースに適当に切り貼りして作った。&lt;br/&gt;
後にして思えば、rep2 の iPhone 用UIが良くできているので、それを参考にするべきだったかも知れない。&lt;br/&gt;
最終的に採用したアルゴリズムは、以下の通り。
&lt;ul&gt;
&lt;li&gt;トップページは、未読があるfeedのリストをメニューとして表示する&lt;/li&gt;
&lt;li&gt;feedを選択すると、item一覧ページを表示する&lt;/li&gt;
&lt;li&gt;item一覧ページは、設定にある上限件数までの表示を目指すが、DBの未読管理の問題から同じstored_onを持つitemは全て表示する&lt;/li&gt;
&lt;li&gt;item一覧ページから次のページに遷移するときに、表示していた最終stored_onでviewed_onを更新し、最終stored_onよりも新しいitemがないときだけhas_unreadをfalseにするようにする&lt;/li&gt;
&lt;li&gt;同じfeedに未読があるときは次のページも同じfeed。なければ次のfeed、次のfeedもなければHomeに帰る&lt;/li&gt;
&lt;/ul&gt;
複数ページあっても一気に既読にする機能とか、いろいろつけたい機能はあるけど、とりあえず読めるようになっちゃったからしばらくいじらないような気もする。&lt;br/&gt;
ソースは、fastladder_mobileに倣ってCodeReposに入れようかとも思ったけど、アカウント取るのが面倒だったのでとりあえず&lt;a href="http://www.wizard-limit.net/trac/fastladder_iphone/wiki/WikiStart"&gt;うち&lt;/a&gt;に入れておいた。
&lt;div class="image-left"&gt;&lt;a href="http://www.wizard-limit.net/mt/pc/archives/assets_c/2009/09/feeds.html" onclick="window.open('http://www.wizard-limit.net/mt/pc/archives/assets_c/2009/09/feeds.html','popup','width=320,height=480,scrollbars=yes,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"&gt;&lt;img src="http://www.wizard-limit.net/mt/pc/archives/assets_c/2009/09/feeds-thumb-160x240.jpg" width="160" height="240" alt="feeds.jpg" class="mt-image-none" style="" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.wizard-limit.net/mt/pc/archives/assets_c/2009/09/items.html" onclick="window.open('http://www.wizard-limit.net/mt/pc/archives/assets_c/2009/09/items.html','popup','width=320,height=480,scrollbars=yes,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"&gt;&lt;img src="http://www.wizard-limit.net/mt/pc/archives/assets_c/2009/09/items-thumb-160x240.jpg" width="160" height="240" alt="items.jpg" class="mt-image-none" style="" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br clear="all"/&gt;</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/_wBt98zhNTA/003893.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003893.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Ruby</category>
            
            
            <pubDate>Wed, 09 Sep 2009 13:15:26 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003893.html</feedburner:origLink></item>
        
        <item>
            <title>回顧録(3)</title>
            <description>大学に入ると、ソフトウェア研究会と言うサークルに入った。
私の大学にはコンピュータ系のサークルが二つあり、固くない方を選んだつもりだったのだが、間違っていた。結果としては良かったが。
同学年の女の子はすべてもう一つのサークルに入り、ソフトウェア研究会は男しかいなかった。
学校の授業ではマックに触った。プログラムはまだなし。お絵描きソフトとか、ワープロ程度。
サークルは週に一度勉強会があり、プログラムを教えて貰った。
夏になると、サークルの合宿があった。福島の温泉で一週間、ほぼ毎日プログラミング。最終日だけ遊び。夜は飲み会。
この合宿が、中学校のVTR部が潰れた時に続いて2度目の人生のターニングポイントだった。
それまで、独学でCを学ぼうとしてもなかなか取っ掛かりがなくうまくいってなかった。
しかし、合宿で教科書にK&amp;Rを指定され、4年生の先輩からポインタについて学ぶことができた。
目の前から急に霧が晴れる感じ。
普段は4年生は顔を出さないし、合宿で教えることもかなり異例だったんだと思う。しかし、私達の代はちょっと変わった奴が多かったので...。
合宿で流行ったのが、タイピング練習ソフト。みんな暇を見つけてはそればっかりやっていた。
それまでの私は我流のタイピングだったが、このソフトのおかげでちゃんとホームポジションに手を置くブラインドタッチをマスターした。画面だけを見てコードが書けると言うのは、想像以上に大切なことだ。
一年生はメキメキ腕を上げ、みんな先輩よりも早くなった。
この合宿でもう一つの大きな出会いがあった。4年生の先輩の一人が、シルバーのユーノス・ロードスターに乗って来たのだ。
それまで、私に取って車とは、親のワンボックスだけだった。車とは移動、輸送の道具だった。
ロードスターは、そんな認識を根底から覆す車だ。でもそれはまた別のお話。

合宿から帰ると秋の学園祭に向けて準備が始まった。
サークルでは、会員が作ったソフトの展示と販売を行う。
当時タケルと言う名前のソフトの自動販売機があったのだが、それをパクった「たけお」と言う箱があった。中に人が入って売り子をするだけのものだけど、なんだかとても良いアイディアに思えた。
私が所属した1年生だけで構成されたチームは、X68000で3Dテトリスを作ることにした。
メインはCで、ワイヤーフレームの描画エンジンはアセンブラだった。
プログラムが3人、絵を書く人、音楽を作る人、シナリオを書く人、部屋を提供する人。
毎日学校が終わると開発部屋に集まった。
できあがったものは私達には大夫満足の行くものだった。これが、最初のチームでの開発経験になった。
500円の値を付けたけど、もちろん内輪にしか売れなかった。

その頃、スティーブ・ジョブズがNeXTを発表した。当時のワークステーションの値段からは信じられないほどの安さで、MACHとか先進的でとても魅力的だった。(当時の私にはほとんど意味がわからなかったんだけど、とにかくエキサイトしたんだ)

2年になると、授業でプログラムが始まった。FORTRAN。
一年の校舎にあったマックではなく、富士通のメインフレームだった。
メインフレームのOSは、それまでの知識ではまったく扱えなかった。MS-DOSとは言わなくても階層構造のファイルシステムやコマンドインタプリタなんてパソコンでも実現できていたのに、メインフレームは違った。
言語自体は難しくなかったので、授業はいつも暇であまり面白くなかった。


3年になると、研究室に所属して、週に一度ゼミと言う授業があった。
私がいた数学系の学科の中で、比較的自由にコンピュータを触らせてくれると言う噂の研究室を選んだ。
その研究室には初代NeXTとSONYのNEWSがあった。(既にNeXTは2代目が出ていた)
当時メジャーだったのはPC-9801とWindows3.1だったけど、私はUNIXにのめり込んだ。
68020とか68030のCPUに、メモリは4Mとか8Mだったけど、Xが動いた。
研究室に顔を出すのは、週に一度のゼミの時間だけで良かったんだけど、休み時間も放課後も、ずっと研究室でワークステーションに触った。
いろいろなフリーソフトをコンパイルし、メールやネットニュースを見た。
NEWSもNeXTも、あまりメジャーとは言えなかったから、フリーソフトをコンパイルするのは結構大変だった。
今みたいにLinuxでconfigure&amp;make一発とはいかなかった。
コンパイルエラーを追いかけ、ソースを修正した。
この経験が、のちに大夫役立っていると思う。

この頃、草の根BBSと言うのが流行っていたので、私も研究室で余っていた1200bpsのモデムを貰ってちょっとやった。
テレホーダイとか入ってなかったので、ちょっとだけ。
Nifty-SERVにも入った。

そして、MOSAICが登場した。
当時はgoogleもyahooもなくて、gooの前身かもしれないNTTのページ(名前を忘れてしまった。日本のWWWページとかそんなの)だけが情報に辿り着く術だった。

4年になると、学科の各研究室にSUNが配置された。ネットワークの管理をまかされたので、学科のサブドメインでメールのやりとりができるようにした。DNSが苦手で、設定を教えてくれない上位ドメインの管理者と喧嘩したりした。
計算機センターに侵入しようとしてアカウント停止されたりもした。
4年の授業で、COBOLがあったが、これだけは習得できなかった。</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/cmJr7_ql8CM/003863.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003863.html</guid>
            
            
            <pubDate>Sat, 22 Aug 2009 12:50:23 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003863.html</feedburner:origLink></item>
        
        <item>
            <title>ゲーム用PC</title>
            <description>相方がゲーム用のデスクトップが欲しいと言うので、DELLのStudio XPS とか言うマシンを購入。&lt;br/&gt;
スペックは、Core i7-920(2.66GHz)、メモリ6G、ATI Radeon HD 4850、750GB SATA HDD (7200回転)、Windows Vista(R) Home Premium SP1 正規版 (日本語版) 64ビットと言った感じ。&lt;br/&gt;
8/2に注文して、8/14に生産完了＆27日頃お届けのメール。8/15に届いて、8/16に出荷済みのメールが届いた。&lt;br/&gt;
さっそくセットアップして、まずはパーティションを切りなおす。Vistaは標準でパーティションの変更ができるんだけど、UIがわかりにくかったので&lt;a href="http://www.partitionwizard.com/"&gt;Partition Wizard Home Edition&lt;/a&gt;を使って切りなおした。(via &lt;a href="http://gigazine.net/index.php?/news/comments/20090815_partitionwizard/"&gt;パーティションのリサイズ・作成・コピー・変換・完全消去などが簡単にできるフリーソフト「Partition Wizard Home Edition」 - GIGAZINE&lt;/a&gt;)&lt;br/&gt;
相方の目的は、Rappelzが快適に動いてプレイ動画がストレスなく記録できること。&lt;br/&gt;
しかし、動かして見ると思ったほどスムーズでない。&lt;br/&gt;
そこで、RappelzをRAMディスクで動かして見ることにする。&lt;br/&gt;
有名なGavotteは64bit版では動かなかったので、&lt;a href="http://projectzero-swb.blogspot.com/2009/06/windows-7-x64ram-disk.html"&gt;Schwarze SQ: Windows 7 x64でRAM Diskを使う&lt;/a&gt;を参考に&lt;a href="http://www.dataram.com/products-and-services/ramdisk"&gt;Dataram RAMDisk&lt;/a&gt;を使って見た。&lt;br/&gt;
まずは、RAMディスクの設定で3GBを確保する。設定ではNTFSが選べないので、Unformattedを選び、Vistaの記憶域の管理からNTFSでフォーマットする。&lt;br/&gt;
RappelsはJ:\Gpotateにインストールしてあったので、そのままRAMDISK(R:)にコピーする。&lt;br/&gt;
RAMDISKの設定で、起動時と終了時にイメージファイルをセーブ/ロードできる設定があるので、K: にイメージファイルを保存するようにしてやった。&lt;br/&gt;
続いて、J:\GpotateをGpotate.origにリネームして、mklink.exe でシンボリックリンクを張る。(Unixのlnと順番が逆)&lt;br/&gt;
&lt;pre class="commandline"&gt;
&gt; mklink /D J:\Gpotate R:\Gpotate
&lt;/pre&gt;
これで、J:\Gpotateにアクセスすると、R:\Gpotateの実体にアクセスされるので、普通にRappelzを起動してやれば、RAMDISKが使われる。&lt;br/&gt;
だいぶ高速化したけど、まだ遅い感じがするのはクライアントの作り上の限界か。&lt;br/&gt;
&lt;br/&gt;
RAMDISKを導入する前に、RappelzをインストールするDISKとプレイ動画を録画するHDDを分けたら良いのではないかと考えて、HDDの増設を検討した。&lt;br/&gt;
ケースを開けてみると、ミニタワーで中はすかすかな癖に、HDDの増設スペースが狭い。&lt;br/&gt;
Radeon 4850と2台目のHDDがぶつかるのではないかと言う感じ。ぎりぎり入りそうな気もするけど・・・。&lt;br/&gt;
あとは、PSPのプレイ動画も録画したくて、ビデオキャプチャについて調べてみたけど、D端子入力で、PCI Expressで、ドライバ/アプリが64bit対応のものは見つけられなかった。PCIで32bitならいくつか選択肢がありそうだったんだけど。&lt;br/&gt;
&lt;br/&gt;
最後に、VistaにWindows 7への無料アップグレード権がついていたので、Dellのページ(&lt;a href="https://win7.dell.com/default.aspx"&gt;https://win7.dell.com/default.aspx&lt;/a&gt;)で申し込もうとしたんだけど、お客様の PC 情報の登録で、サービスタグを入力して「認証する」ボタンを押しても、そこから先に進まなかった。FirefoxでもIEでも同じだったので、サイト側に何か問題があると思われる。(と思ってググったら、いくつか同じ症例がひっかかった。時間を置いてやってみて駄目だったら、サポートに電話するくらいしかないらしい)</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/kmYIxhKx0wU/003853.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003853.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Hardware</category>
            
            
            <pubDate>Sun, 16 Aug 2009 21:13:09 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003853.html</feedburner:origLink></item>
        
        <item>
            <title>iPhoneでVPN(2)</title>
            <description>iPhoneのSIPクライアントを使いたくて、VPN周りの見直しを行った。&lt;br/&gt;
そもそも、pptp周りは過去に2回エントリを書いているのだけれど、現在の状況はそのときとは変わっている。&lt;br/&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.wizard-limit.net/mt/pc/archives/000758.html"&gt;poptopでpptp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.wizard-limit.net/mt/pc/archives/003327.html"&gt;iPhoneでVPN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
一番大きな違いは、当時はFreeBSDがpppoeクライアント＆ルータ＆pptpサーバだったのに対して、現在はフレッツのルータがpppoeクライアント＆ルータで、FreeBSDはpptpサーバのみをやっていると言う事。&lt;br/&gt;
今回、動くまでにいろいろやったので、一通り書いてみるけど、どれかは不要かも知れないが組み合わせの検証をするのが面倒なのでそこまではやらない。
&lt;ul&gt;
&lt;li&gt;FreeBSDがルータではなくなったので、/etc/rc.conf で gateway_enable="true"をコメントアウトしてあったけれど、pptpサーバとしてIP転送が必要なので元に戻した。&lt;/li&gt;
&lt;li&gt;/etc/ppp/ppp.conf で、pptpクライアントに割り当てるネットワークセグメントをLANのものとは分けた。(LANは192.168.0.0/24)
&lt;pre class="textfile"&gt;
 set ifaddr 192.168.1.1 192.168.1.201-192.168.1.210 255.255.255.0
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;/etc/ipf.rules で、pptpが使用するtun0を通すようにした。
&lt;pre class="textfile"&gt;
pass out on tun0 all head 250
pass in on tun0 all head 200
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;フレッツのルータRT-S300SEの設定で、静的ルーティングの設定と言うのがあるので、192.168.1.0/24宛のルーティングをFreeBSDのLAN側アドレス(192.168.0.2)に設定した。&lt;/li&gt;
&lt;/ul&gt;
後は、iPhoneのSIPクライアントでも設定があったんだけど、そちらはあまり大きな声で言いたくないのでここには書かない。&lt;br/&gt;
&lt;br/&gt;
今回やっていて良くわからなかったのが、iPhoneのtracerouteの動き。3G回線と、VPNのppp0があるときに、-i オプションでppp0を指定してあげないと VPN側にtracerouteできなかった。(これのおかげで、設定はおかしくないのにうまくいっていないと思って随分設定を変えてしまった)&lt;br/&gt;
ルーティングテーブルは、defaultが2行あって、最初にVPN側が出てるんだけどなあ。</description>
            <link>http://feedproxy.google.com/~r/wizard-limit/mt/pc/~3/RdAcXDoNadU/003846.html</link>
            <guid isPermaLink="false">http://www.wizard-limit.net/mt/pc/archives/003846.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">FreeBSD</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Network</category>
            
            
            <pubDate>Mon, 10 Aug 2009 16:02:50 +0900</pubDate>
        <feedburner:origLink>http://www.wizard-limit.net/mt/pc/archives/003846.html</feedburner:origLink></item>
        
    </channel>
</rss>
