2004年7月のアレ
2004年7月28日
リンク一覧のステータスチェックをするプログラムを動かしてみると、 途中でDNSが応答しなくなってタイムアウトになるようだ。 どうも奇妙な現象である。
@nifty で 1000 サイトをチェックする処理を起動すると、 376.001 秒かかっている。 この数値は Junit が表示している時間なので、 厳密にいえば他の処理も含んでしまっているが、 だいたいこの程度だということで。
ところが、同じテストを OCN で行うと、 70.672秒、76.06秒、89.108秒、63.992秒、 といった感じで、約1/5の時間しかかからない。 これはDNSが途中で反応しないのが原因なのは分かっているのだが、 @niftyのDNSが重いのか、 それとも自宅のDNSがうまく設定されていない?
§
キーワードの関連グラフを作成したい。 あるキーワードに関連のあるキーワードをFOAFみたいな感じで表示したいのだ。 どういう処理がいるだろうか?
ArrayList getNextKeywords(String keyword)
あるキーワードを指定して、それに関連のあるキーワード一覧を返す。 関連キーワードが一つもない場合は null を返す。 判定処理は、
boolean hasRelation(String key1, String key2);
こんな感じ? 閾値を指定できるようにしたいなら、
boolean hasRelation(String key1, String key2, int limit);
閾値って何かというと、キーワードにランクを付けておいて、 指定した値よりもランクの低いキーワードは見なかったことにしようというのだ。
§
Fedora でテキストデータを MySQL にコピーするような処理を実行してみると、 その間、CPUが100%の状態になってしまう。 なぜだろ?
2004年7月27日
「らんだむCGりんく」のデータを見直している。 ちょっとデータが古くなりすぎていて、 これでは役に立たないかというので。 大きな変更としては、 justnet が終了していること、 u-page が終了していること。 あと、8月末で member.nifty.ne.jp が終了するということで、 移転情報を集める必要がある。
単純に移転してくれたら簡単なのだが、 世の中そうは甘くなくて、 分裂するサイトとかあったりして大変。
2004年7月20日
サイトの状態を調査する処理。 単純に複数のサイトを順に調べると、 応答がないサイトの所で止まってしまう。 そこで、スレッドを使って並行処理し、 タイムアウトは例外を発生させる。 という話をかなり前に書いた。 流れ的には、こんな感じ?
while (it.hasNext()) { while (スレッドに空きがない) { // 空きができるまで待つ } target = it.next(); スレッドを追加する }
it は Iterator である。 スレッドの空きというのはヘンな表現だが、 単純に調査対象サイトがある限りどんどんスレッドを立ち上げてみると、 際限なくスレッドが立ち上がってしまう。 つまり、スレッドがサイトの状態を確認するよりも、 スレッド立ち上げの方が速いのである。 ということは、1万ページに対して現在もあるかどうか調べようと思ったら、 1万とは言わないにしても、それに近い数のスレッドが起動してしまうことになる。 これは面白くないので、 同時に立ち上げるスレッドの数を制限しようというのだ。 そこで、 問題はスレッドの数の制限に届いたか、あるいはまだ余裕があるのか、 どうやって調べるのか、ということになる。
singleton のカウンタを作る、なんてのは定番っぽいですが、 ところで、GoF のデザインパターンの中で最も難しいのはどれだと思いますか?
私見としては、断然 singleton。 これが一番難しい。 蛇足しておくが、 教科書とかによく出ている、
public Hogehoge getObject() { if (hogehoge == null) { hogehoge = new hogehoge(); } return hogehoge; }
が使えないことは言うまでもないですよね? 間違っているというかバグとまでは言わないが、 スレッドでこういうコードを使うと一発でアウト。 hogehoge == null の判定で true になったので new する間に別のスレッドが new してしまうかもしれないからだ。 ではどうするか、という話。
サイトを調査するスレッドを singleton のカウンタで管理しようと思ったら、 何か奇妙なことになったのだが、 これが原因っぽい。
2004年7月14日
Xoops の kickup がうまくいかないので、 Eclipse 3.0 の Character Encoding を MS932 から EUC_JP に変更してみようとしたが、 要するにこれはデフォルトエンコーディングの話だから、 InputStreamReader を作る時点で指定すればよろし。 つまり、
Reader r = new InputStreamReader(buffer, getCharsetString());
みたいな?
で、問題は HTML の中に META で charset を指定している場合なのだが、 これってどうすれば処理できるのか? ナニがいいたいかというと、 HTML の中の META タグを読むためには、 HttpURLConnection::readContents(Reader) を呼び出す訳だが、 これを呼び出す前に charset を指定しなければならない罠。 charset を指定するためには HTML の META タグを読むために HttpURLConnection::readContents(Reader) を呼び出さないといけない罠。
人生至る所バケツの穴。
もっとも、http の header part で charset が来ているはずだから、 それに応じた処理をしておけば桶というのはもっともだ。 ただ、世の中には、 http の header part と META の指定内容が違うという、 とんでもないサーバーもあることにはある。 そういうのは無視するのもアリだけど。 header part で charset 指定してこない、という場合はどうだろ?
§
Cookie のハマリがナニなのでメモっておくと、
Cookie はサーバーから Set-Cookie という属性で送られてくる。 基本的に、Cookie の値とか、pathとか、その他いろいろ。
ということで、 HttpURLConnection huc が connect した状態として、 Map map = huc.getHeaderFields(); でヘッダの属性を Map として受け取った後、
Set keyset = map.keySet(); Iterator it = keyset.iterator(); while (it.hasNext()) { Object object = it.next(); if (object == null) continue; if (object.toString().equals("Set-Cookie")) { // (List) map.get(object); で Cookie を List として受け取る } }
みたいな感じでサーバーから Cookie を受け取る。
クライアントからは、 Cookie という属性でサーバーに送る。 送るのは値だけでいい(?)。 送る値が getCookieString() で受け取れるように作ってあるとして、
huc.setRequestProperty("Cookie", getCookieString());
こんな感じ?
2004年7月13日
風邪ぽ。 一日寝る。
2004年7月9日
Eclipse 3.0 のダウンロード。
eclipse-SDK-3.0-win32.zip
, eclipse-SDK-3.0-linuk-motif.zip
, eclipse-SDK-3.0-linuk-gtk.zip
本体。
eclipse-Automated-tests-3.0.zip
Junit。
eclipse-examples-3.0.zip
, eclipse-examples-3.0-win32.zip
例?
その他にもいろいろダウンロードした。結構面倒。 一括ダウンロードってどうすればできるのだろうか?
§
そういえば渋谷 TSUTAYA が Wカード半額キャンペーンを今日からヤルみたいな?
§
Xoops。 css を指定する方法が分からないので、 どこで HTML のヘッダーを読み込んでいるのだろうか、と思って、 header.php を見ていた。 なお、そのまま引用したらリストが横にすご~く長くなってしまってあらゆる意味で望ましくないような気がしたので、 適当に改行して空白を調整したりしてある。
if ($xoopsUser != '') { $xoopsTpl->assign(array( 'xoops_isuser' => true, 'xoops_userid' => $xoopsUser->getVar('uid'), 'xoops_uname' => $xoopsUser->getVar('uname'), 'xoops_isadmin' => $xoopsUserIsAdmin) ); if (!empty($xoopsModule)) { // set page title $xoopsTpl->assign('xoops_pagetitle', $xoopsModule->getVar('name')); if (preg_match("/index\.php$/i", xoops_getenv('PHP_SELF')) && $xoopsConfig['startpage'] == $xoopsModule->getVar('dirname')) { $block_arr =& $xoopsblock->getAllByGroupModule( $xoopsUser->getGroups(), $xoopsModule->getVar('mid'), true, XOOPS_BLOCK_VISIBLE); } else { $block_arr =& $xoopsblock->getAllByGroupModule( $xoopsUser->getGroups(), $xoopsModule->getVar('mid'), false, XOOPS_BLOCK_VISIBLE); } } else { $xoopsTpl->assign('xoops_pagetitle', $xoopsConfig['slogan']); if (!empty($xoopsOption['show_cblock'])) { $block_arr =& $xoopsblock->getAllByGroupModule( $xoopsUser->getGroups(), 0, true, XOOPS_BLOCK_VISIBLE); } else { $block_arr =& $xoopsblock->getAllByGroupModule( $xoopsUser->getGroups(), 0, false, XOOPS_BLOCK_VISIBLE); } } } else { $xoopsTpl->assign(array('xoops_isuser' => false, 'xoops_isadmin' => false)); if (isset($xoopsModule)) { // set page title $xoopsTpl->assign('xoops_pagetitle', $xoopsModule->getVar('name')); if (preg_match("/index\.php$/i", xoops_getenv('PHP_SELF')) && $xoopsConfig['startpage'] == $xoopsModule->getVar('dirname')) { $block_arr =& $xoopsblock->getAllByGroupModule( XOOPS_GROUP_ANONYMOUS, $xoopsModule->getVar('mid'), true, XOOPS_BLOCK_VISIBLE); } else { $block_arr =& $xoopsblock->getAllByGroupModule( XOOPS_GROUP_ANONYMOUS, $xoopsModule->getVar('mid'), false, XOOPS_BLOCK_VISIBLE); } } else { $xoopsTpl->assign('xoops_pagetitle', $xoopsConfig['slogan']); if (!empty($xoopsOption['show_cblock'])) { $block_arr =& $xoopsblock->getAllByGroupModule( XOOPS_GROUP_ANONYMOUS, 0, true, XOOPS_BLOCK_VISIBLE); } else { $block_arr =& $xoopsblock->getAllByGroupModule( XOOPS_GROUP_ANONYMOUS, 0, false, XOOPS_BLOCK_VISIBLE); } } }
何をやっているのかよく分からないが、 同じような処理が頻繁に出てくる。 例えばこれ。
if (!empty($xoopsOption['show_cblock'])) { $block_arr =& $xoopsblock->getAllByGroupModule( XOOPS_GROUP_ANONYMOUS, 0, true, XOOPS_BLOCK_VISIBLE); } else { $block_arr =& $xoopsblock->getAllByGroupModule( XOOPS_GROUP_ANONYMOUS, 0, false, XOOPS_BLOCK_VISIBLE); }
条件によって処理を変えているのだが、 $block_arr の後の処理で違うのは「true」と「false」の所だけだ。 となると、なぜ if で分岐したのかよく分からない。 素直に書けば、
$block_arr =& $xoopsblock->getAllByGroupModule( XOOPS_GROUP_ANONYMOUS, 0, !empty($xoopsOption['show_cblock']), XOOPS_BLOCK_VISIBLE);
と、これだけで済むと思うのだが。 もっとも、この1行が長すぎるという意見はあるかもしれない。 だったら、真偽を変数に入れるのが基本技。
$b =!empty($xoopsOption['show_cblock']); $block_arr =& $xoopsblock->getAllByGroupModule( XOOPS_GROUP_ANONYMOUS, 0, $b, XOOPS_BLOCK_VISIBLE);
よく見ると、さらに外のレベルの処理も似たようなものが多い。 コピーして変更するという、典型的なナニをした時にそうなりがちなものだが、 いくら何でも Xoops のソースがそういうレベルというのはあり得ないと思うので、 何か理由があるのだろうが、それが分からない。
もっと分からないのは、 最初に引用したソースで、 最初の $xoopsModule の判定、
if (!empty($xoopsModule)) {
ところが、2つ目は、
if (isset($xoopsModule)) {
では、empty と isset は何が違うのか? PHPのマニュアルを見ると、 どちらも 「変数がセットされているかどうかを検査する」 と、全く同じ文章になっている。 後の説明を見れば分かるのだが、 実は empty と isset は、 変数 $var に 0 をセットした場合のふるまいが違う。 それを除けば、 !empty と isset は同じ結果になるのである。
未定義 | 0を代入 | 1を代入 | |
---|---|---|---|
isset | false | true | true |
empty | true | true | false |
!empty | false | false | true |
問題は、このコード中でそれを使い分けた意図なのだが、 すみません、全然分かりません(^^;)。
分からないということは、 リファクタリングでも触らないしかない。 とりあえず共通の処理をくくりだす。 因数分解しているような感じだ。
if ($xoopsUser != '') { $xoopsTpl->assign(array( 'xoops_isuser' => true, 'xoops_userid' => $xoopsUser->getVar('uid'), 'xoops_uname' => $xoopsUser->getVar('uname'), 'xoops_isadmin' => $xoopsUserIsAdmin )); $bEmptyOrNot = !empty($xoopsModule); $group = $xoopsUser->getGroups(); } else { $xoopsTpl->assign(array( 'xoops_isuser' => false, 'xoops_isadmin' => false )); $bEmptyOrNot = isset($xoopsModule); // why? $group = XOOPS_GROUP_ANONYMOUS; } if ($bEmptyOrNot) { // set page title $xoopsTpl->assign('xoops_pagetitle', $xoopsModule->getVar('name')); $bresult = preg_match("/index\.php$/i", xoops_getenv('PHP_SELF')) && $xoopsConfig['startpage'] == $xoopsModule->getVar('dirname'); $block_arr =& $xoopsblock->getAllByGroupModule( $group, $xoopsModule->getVar('mid'), $bresult, XOOPS_BLOCK_VISIBLE ); } else { $xoopsTpl->assign('xoops_pagetitle', $xoopsConfig['slogan']); $bresult = !empty($xoopsOption['show_cblock']); $block_arr =& $xoopsblock->getAllByGroupModule( $group, 0, $bresult, XOOPS_BLOCK_VISIBLE ); }
ページタイトルを assign する処理と、 $block_arr をセットする処理、 これも共通部分が多いのでまとめることができる。 どこまで一括した方がいいのかというと、 「1箇所変更すれば済む」 という状態にするためには、 似た処理は存在しない、 という所まで極めた方がいいかもしれないが、 やりすぎは、かえってよくない場合もある。
PHP で一番困るのが変数のスコープの分かりにくさで、 C, C++, Java 等では、ブロックの中という明確な範囲があるので気楽に変数を使えるのだが、 PHP の場合、 うっかり使った変数がだぶってしまうとか、 そういう危険が常についてまわる。 Perl も同じわけだが、 だったら function とか sub に分割しろ、というポリシーなのだろう。 とりあえず、まとめたらこんな感じか。
if ($bEmptyOrNot) { $pagetitle = $xoopsModule->getVar('name'); $bresult = preg_match("/index\.php$/i", xoops_getenv('PHP_SELF')) && $xoopsConfig['startpage'] == $xoopsModule->getVar('dirname'); $v = $xoopsModule->getVar('mid'); } else { $pagetitle = $xoopsConfig['slogan']; $bresult = !empty($xoopsOption['show_cblock']); $v = 0; } $xoopsTpl->assign('xoops_pagetitle', $pagetitle); $block_arr =& $xoopsblock->getAllByGroupModule( $group, $v, $bresult, XOOPS_BLOCK_VISIBLE );
$v というのは変数名がよくないのだが、 これ、一体何の変数なのか分からなかったので仮にそういう名前にしただけの話なのだ。 そういう意味では $bresult というのも最悪より一歩手前の名前で $a よりはマシ、程度に過ぎないが。
2004年7月8日
いかに売れるものを作るかではなくて、 ユーザーにどのように使ってもらえるか、を考えろ。
苦労して身に付けなければダメ。
§
WideStudio のメモ。 インストール後に再起動しろというメッセージが出る。 再起動しないとダメらしい。 この時に、元から出ているメッセージに再描画のイベントが行かない。 バグ?
プロジェクトの作成のメッセージウィンドウが常に最前面に表示される。 このドキュメントを書くのにも大変苦労する。 常に最前面に表示するというのは、 システムアプリケーションの緊急な事態で、 他のアプリケーションの操作を一切禁止しなければならないとか、 絶対に他のウィンドウに隠れてはいけない特別な理由がある場合とか、 そういう時に限るべきである。
チュートリアルは、つまらない間違いが多い。 クオリティは低い(初校前の状態相当?)。 但し、ドキュメントだけでなく、 WideStudio そのもののクオリティも低い。
btn_ep をダブルクリックすると、と書いてあるが、 new_ep の間違い。
2004年7月6日
安定性と意外性の話を書こうとしたのだが、 また後で。
2004年7月5日
すげー暑かったような気がするのだが、 体温を測ったら37℃超。 ヤバ。 しかし、求職中でもお中元は贈らなくてはいけないので、 新宿高島屋に行く。 あんなにガラガラのお中元コーナーは初めて見た。
何か隣の人がトラブっていましたが。 品物コードを入れたのに、 そんな品物はない、みたいなエラーが出ていて先に進めないと。 DBの登録ミスか何かだと思うのだが、 現場はパニクっていた。 手作業で別伝票起こすとか、そういう裏技ないのかな。
§
とある所の Office 2000 Personal (でしたっけ?)を upgrade して、 Office 2003 Standard に。 事の発端は「PowerPoint が仕事に必要なので入れたい」 ということで、 Office を丸ごと upgrade しなくても PowerPoint だけでいいのだが、 PowerPoint だけ購入するのと Office 2003 Standard に Upgrade する場合の差額が数百円という罠。 ちなみに、 Office 2002 Standard に Upgrade した場合は、差額0円。 どういう価格設定なのかよく分からないが、 とりあえず w2k を使っているということで、 Office 2003 Standard にしてみた。
で、インストールしたわけだが、 まあこりゃ何というか分かりにくいですねぇ、 多分「推奨」となっている upgrade を実行すると、 PowerPoint がインストールされない罠。 もしかして、既に持っている機能だけバージョンアップできるということで、 新機能はインストールできないのか、 とか一瞬思ったが、そんなことはない。 upgrade の後に、カスタムインストールで機能追加してもokのようだが、 今回は完全インストール(でしたっけ?)を実行した。 これで問題なし。 既にインストールされている office の CD-ROM を用意しておけという話なので、 倉庫から Office 2000 の箱を引っ張り出してきて、横に置いてスタンバイしたのだが、 結局一度も使わない罠?
まあ無事インストールできれば別に細かい話は気にしない。 その後、常識の Office Update を実行。 これが曲者で、 このPC、例によってPCカードを無線LANとCD-ROMドライブで共有するタイプなので、 ネットワークに接続している時には CD-ROM が使えない。 前回の経験では、CD-ROM を入れろというメッセージが出た時点で無線LANを切り離して、 CD-ROMドライブを接続、という手順で問題なかった。 ただ、今回は「用意しろ」というメッセージが出たのに、 やはり結局一度も CD-ROM を入れる場面がないまま終了。
もしかして、 マイクロソフト、 pcの横に製品のCD-ROMを置くだけで正規ユーザーを識別する技術を開発したのか?
2004年7月3日
そういえば、 そろそろ メンバーズホームページ、追い出されるのか。 引越し先を整備しないといかんナー。
2004年7月2日
某書の原稿遅れている。 ヤバい~。 もっとも、量的におかしいというか、多いような気がするのだが、 必死で書いても半分ボツ、みたいな?
ハマっているポイントは、まず、 Eclipse に CDT をインストールできない。 これは CDT の最新版を持ってきてしまったので、 Eclipse を 3.x にしないとダメらしいということか。
もっとキツい話は、 MicroSoft の無償開発系。 Visual C++ Toolkit 2003 をインストールした状態で .NET Framework SDK をインストールすると、 いろいろ普通ではない手順になってしまって、 既に書いた原稿と食い違ってしまう。 これを修復するのに大変な騒ぎになったのである。
で、無償のコンパイラは何がいいのか、 という話を書きたいのだが、 Eclipse で Java 使えとは書けないっスよ、やっぱ。
§
プログラミング言語系のコミュニティのクオリティの話。 FPROG のそれ系の会議室に比べると、 3~4レベル、初心者というか素人にシフトした感じのものが多い。 もっとも、これは当たり前の話で、 規模が数十名~数百名になってしまうためだと思う。 FPROG の場合、全盛期には数万人の会員、実際に活動している人だけでも数千人、 その中から一番上の数%の人が議論していたのだから、 当然、レベルは高かった。 もっとも、それに追いつけないという人も続出したようで、 なかなか世の中は厳しい。
逆に考えると、 インターネットの場合、 そういうレベルでないと初期コミュニティが形成しにくいという現象があるのかもしれない。 ハイレベルな掲示板も、当然存在しているが、 世の中にハイレベルなプログラマーが少ないとすれば、 それをインターネット上の膨大な数のコミュニティで奪い合うわけだから、 平均するとレベルダウンするのは必然で、 探せばハイレベルの所はある、という状況になるのではないかと。 言い換えると、誰か一人ハイレベルな人がいると、 それなりのクオリティにはなる。 もう一人いて議論になれば、相乗効果が発生する。 ところが、インターネットだと、わざわざ対立意見を持つ人が同じ場所にいる必要はない。 @niftyというか、NIFTY-Serveというのは、 それしかない、ということが多少は効いていたのだと思う。
2004年7月2日
PHP の続き。 前回で、他にも修正必要な箇所があると書いたが、すぐ後に出てくる、
for($i=0;$i<5;$i++){ //テーブルで整形して表示
この辺りだけかな? だとすると、5というマジックナンバーを$sizeにするだけで済むか。
for ($i = 0; $i < $size; $i++) {
少し前後するが、 showbyQ4() という関数。
foreach($lines as $l){ //感想がある場合,それをキーとして配列を作成 $op=explode(",",$l); $key=$op[20]; if($key!=""){ $memo[$key]++; } } // **** 途中省略 **** foreach($memo as $key => $value){ echo"<tr><td>$key</td></tr>"; }
キーにターゲットとなる情報を入れて値は使わない、 というような書き方は perl でよく出てくると思う。 Java でいうところの set のような使い方である。 PHP は添え字を指定しないと自動的に最大のインデックスを追加してくれたと思うので、 次のような書き方も可能だが、
foreach ($lines as $l) { $op = explode(",", $l); $comment = $op[20]; if ($comment != "") { $memo[] = $comment; } } // **** 途中省略 **** foreach ($memo as $value){ echo"<tr><td>$value</td></tr>"; }
これだと、同じ感想が100個あったときに、 100行の同じ感想が表示されてしまう。 キー側に感想を追加することで、重複を自動的に避けることができるのだ。
関係ないけど、雰囲気的には、
$comment = explode(",", $l)[20];
みたいな書き方をしたくなるが、どうだろうか?
§
あと、今頃気付いたのだが、img タグの height、width 属性が、 " で quote されている処理と、数字をそのまま書いてある処理がある。 どちらでもいいのなら統一した方がいいと思う。
もう一つ、これはリファクタリングも何も、 ソースの意味が分からないので変更しようがなかったのが、 テーブルの $length を求める処理。 td タグは width が 350 で固定になっている。 画面に表示される幅を揃えるという意味だと思われる。 それは分かるとして、 そこに出すヒストグラムの width を、 350 * 変数で計算している処理と、300 * 変数で計算している処理があるのだ。 350 というのは分かる。 td タグの width が 350 だからだ。 回答が全て1つの選択肢に集まったときに、 widthが350となり、これが最大の長さ、ということなのだろう。 分からないのは 300 という値である。 これは一体どこから出てきたのだろうか?
2004年7月1日
お昼のTV見ていたら、みのもんた氏がナンバ歩きの話をしていた。 日本古来の歩き(走り)方だと紹介しているのだが、 そんなに昔まで行かなくても、 要するにいわゆる「肩で風切って歩く」ってアレだよな、確か。 多分ガクラン着て歩くと格好いいぞ。