Tracker_list プラグインの無駄な処理

  • ページ: BugTrack2
  • 投稿者: 名無しさん
  • 優先順位: 低
  • 状態: 完了
  • カテゴリー: プラグイン
  • 投稿日: 2007-05-30 (水) 01:32:59
  • バージョン:

[fixed] fixed heading anchor を削除する処理が過剰 (二回目は不要のはず)

次の部分の処理が無駄だと思うのですが、いかがでしょう。

// $Id: tracker.inc.php,v 1.36 2007/03/29 15:05:52 henoheno Exp $
(中略)
class Tracker_list
{
(中略)
	function add($page,$name)
	{
(中略)
		$source = plugin_tracker_get_source($page);
		if (preg_match('/move\sto\s(.+)/',$source[0],$matches))
		{
(中略)
			return $this->add($page,$name);
		}
		$source = join('',preg_replace('/^(\*{1,3}.*)\[#[A-Za-z][\w-]+\](.*)$/','$1$2',$source)); //無駄だと思う部分

(中略)
function plugin_tracker_get_source($page)
{
	$source = get_source($page);
	// 見出しの固有ID部を削除
	$source = preg_replace('/^(\*{1,3}.*)\[#[A-Za-z][\w-]+\](.*)$/m','$1$2',$source);
	// #freezeを削除
	return preg_replace('/^#freeze\s*$/im', '', $source);
}

plugin_tracker_get_source の途中、preg_replace でアンカー名を消す置き換えをしているのに、
plugin_tracker_get_source で呼び出したソースに、もう一度アンカー名を消す置き換えをしようとしています。
この部分は、

-		$source = join('',preg_replace('/^(\*{1,3}.*)\[#[A-Za-z][\w-]+\](.*)$/','$1$2',$source));
+		$source = join('',$source);

と修正したほうが、よいと思います。

  • コメントありがとうございます。この件、正規表現も完全一致のようですね。私も特に違和感を感じませんでした。 -- henoheno 2007-06-10 (日) 21:43:48
  • 確認しました。この部分は完了ですね。 -- 2007-06-11 (月) 19:33:51

[fixed] unset() すべきリソース

  • BugTrack2/159 を見たので、これも修正候補という事で追加。
    // $Id: tracker.inc.php,v 1.36 2007/03/29 15:05:52 henoheno Exp $
    // Copyright (C) 2003-2005 PukiWiki Developers Team
    (中略)
    class Tracker_list
    {
    (中略)
    	function add($page,$name)
    	{
    (中略)
    		if ($this->rows[$name]['_match'] = preg_match("/{$this->pattern}/s",$source,$matches))
    		{
    +			unset($source);
    			array_shift($matches);
    			foreach ($this->pattern_fields as $key=>$field)
    			{
    				$this->rows[$name][$field] = trim($matches[$key]);
    			}
    		}
    	}
    (中略)
    	function toString($limit=NULL)
    	{
    (中略)
    		foreach ($this->rows as $key=>$row)
    		{
    			if (!TRACKER_LIST_SHOW_ERROR_PAGE and !$row['_match'])
    			{
    +				unset($this->rows[$key]);
    				continue;
    			}
    			$this->items = $row;
    			foreach ($body as $line)
    			{
    				if (trim($line) == '')
    				{
    					$source .= $line;
    					continue;
    				}
    				$this->pipe = ($line{0} == '|' or $line{0} == ':');
    				$source .= preg_replace_callback('/\[([^\[\]]+)\]/',array(&$this,'replace_item'),$line);
    			}
    +			unset($this->rows[$key]);
    		}
    		return convert_html($source);
    	}
    1つ目のTracker_list->add() でのunset は、「1ページ分のソース×2」を解消するためなんですが、これはページのデータ量しだいで効果が変わってしまいそうです*1
    2つ目のTracker_list->toString() でのunset は、「リストの各項目に置き換えたページのデータを順次消していく」です。これも総ページ数が少ないうちはあまり効果がないかもしれません*2
    って効果を実証できてない。テストを準備して~の時点でつまづいてるせいか。 -- 2007-06-10 (日) 14:12:21
  • 一つ目の unset() の意図はわかりました。問題ないかと思います。二つ目と三つ目のunset() は $this-> rows を少しでも減らそうとしていますね。気持ちは解るのですが、これをやった場合、オブジェクトの toString() を二回以上呼・・・ぶ事なんてまず無いと思いますが、呼んだ時の挙動が不定になってしまいます。ちょっと破壊的に見えて怖いです。なおどのみちこのオブジェクトを作成した関数は toString() を呼んだ後すぐにオブジェクトを丸ごと開放するでしょう。 -- henoheno 2007-06-10 (日) 21:48:14
  • 確認しました。2つ目はreturn でtoString() を呼んでいるので、しなくてもいいかなとも思いつつ書いていたので、かまいませんよ。 -- 2007-06-11 (月) 19:33:51

[fixed] 不要なフィールドをテーブルに抱え込んでいる

  • そもそも、予約語やテンプレート名のページ*3で設定したもの以外の項目を、$this->rows に放り込む必要があるのかな?という修正案。
    // $Id: tracker.inc.php,v 1.36 2007/03/29 15:05:52 henoheno Exp $
    (中略)
    class Tracker_list
    {
    (中略)
    	function Tracker_list($page,$refer,&$config,$list)
    	{
    (中略)
    		while (count($pattern))
    		{
    			$this->pattern .= preg_replace('/\s+/','\\s*','(?>\\s*'.trim(array_shift($pattern)).'\\s*)');
    			if (count($pattern))
    			{
    				$field = array_shift($pattern);
    				$this->pattern_fields[] = $field;
    				$this->pattern .= '(.*)';
    			}
    		}
    +		$this->pattern_fields = array_intersect($this->pattern_fields, array_keys($this->fields));
    		// ページの列挙と取り込み
    		$this->rows = array();
    少しでもデータが減った分、後の処理が軽くならないかな~。 --2007-06-10 (日) 14:40:03
  • この件は雰囲気は伝わったものの、(私がTracker_list を理解し切れていないこともあり) 実装の意味が解りませんでした。array_intersect() でいいのかどうかとか、説明では $this->rows とあるのにコードでは $this->pattern_fields であったりする点など。もし何かあれば追記願います。 -- henoheno 2007-06-10 (日) 21:51:04
  • 上の部分で、$this->pattern に各リスト対象ページを項目ごとに分割する正規表現を、$this->pattern_fields に$this->pattern の正規表現のサブパターンリストを収得しています。
    Tracker_list->add() の最後で、preg_match('/' . $this->pattern . '/s',implode('', $source),$matches) を使って得た$matches から、
    各項目名の配列に収納するために、foreach ($this->pattern_fields as $key=>$field) を使っています。
    例として、デフォルトの:config/plugin/tracker/default/page から得られるのは、
    $this->pattern = '(?>\s*\*\s*)(.*)(?>\s*-ページ\:\s*)(.*)(?>\s*-投稿者\:\s*)(.*)(?>\s*-優先順位\:\s*)(.*)'.
    		'(?>\s*-状態\:\s*)(.*)(?>\s*-カテゴリー\:\s*)(.*)(?>\s*-投稿日\:\s*)(.*)(?>\s*-バージョン\:\s*)(.*)'.
    			'(?>\s*\*\*\s*メッセージ\s*)(.*)(?>\s*----\s*)(.*)(?>\s*\s*)'
    $this->pattern_fields = Array ( [0] => Summary [1] => _refer [2] => Proposer [3] => Severity [4] => Status
    		[5] => Category [6] => _date [7] => Version [8] => Messages
    			[9] => _block_comment )
    	見にくくなるので適当に加工してます。
    です。
    $this->pattern_fields = array_intersect($this->pattern_fields, array_keys($this->fields) の部分は、
    「$this->pattern_fields の各値の中で、予約語など($this->fields の各キー名)に存在しないものがあれば、その値が入っているキーをunset した配列を、$this->pattern_fields に代入しなおす」
    という処理です。 入力ミスがなければ、該当するのはブロック型プラグイン(_block_プラグイン名)のみとなります。 上の例で言えば、水平線以降のコメント部分が該当します。

    上の例だと、実際に$this->rows に入るのは各ページ10項目ですが、 _block_comment をリストの表示につかわない*4であろう、ということと、
    同じプラグインが複数回使われたとしても、今の置き換えルールではその判別ができない(同じフィールド名になってしまう)という理由から、
    設定されていない項目のデータを得なくてもかまわないだろう、という判断でこの修正案を挙げました。 -- 2007-06-11 (月) 11:33:43

  • :confing/tracker/default の場合、 array_intersect() で消えるのは [_block_comment] (#comment) 。同様に、ブロック型プラグインは消えるだろう -- henoheno 2007-09-09 (日) 21:34:23
    • このパッチの主張が「[_block_XXX] についての $this->pattern_fields は不要」であると仮定するとして -- henoheno 2007-09-09 (日) 21:38:51
    • そうならば array_intersect() を後からかけるより、whileの内部で isset() を使い、そもそも $this->pattern_fields に無駄な項目を追加しない様にするのが良さそうかな・・・ -- henoheno 2007-09-09 (日) 21:43:07
    • Tracker_list::add() を見てようやく理解できました。確かにblock pluginの名前は、tracker_list が抱えるテーブルのセルとして保持する必要がありません。 -- henoheno 2007-09-09 (日) 22:10:32
    • cvs:plugin/tracker.inc.php (r1.49) -- henoheno 2007-09-09 (日) 22:46:06
    • 元の提案のままだと block plugin などをかわすための仮想フィールド(pseudo fields とでも呼びましょう)を capture するように $pattern で指定したままだったので、block plugin の後ろにフィールドを配置した場合に、それ以降のデータがずれて格納される恐れがある様でしたので、pseudo fields をそもそもcaptureしない様に修正しました。これで、勘違いでもしていなければメモリのオーバーヘッドが減るはずです。 -- henoheno 2007-09-09 (日) 22:47:44
  • 動作の確認しました。この部分の変更については特に問題もなく、きちんと動作していました。offical のようにTracker_list プラグインをたくさん使っているサイトは、メモリの負荷対策にもなってしまいそうですよね。 -- 2007-09-10 (月) 19:39:17

[rejected] その他: $this->order

  • cvs:plugin/tracker.inc.php (v 1.38) の中に消し忘れがあったので報告を。
    class Tracker_list
    {
    (中略)
    	function sort($order)
    	{
    		if ($order == '')
    		{
    			return;
    		}
    		$names = array_flip(array_keys($this->fields));
    		$this->order = array();//これ
    		foreach (explode(';',$order) as $item)
    		{
    初期化処理をTracker_list->Tracker_list() に移した時に、見逃したのだと思います。 -- 2007-06-11 (月) 19:33:51
    • $this->order は、Tracker_list::sort() を実行する度に初期化する様にしました。なぜならば $this->order は Tracker_list::sort() に与えた命令を分解した結果を収める入れ物であるようだからです。これを毎回きちんとリセットしてくれない様だと、sort() を二回以上コールした時*5に意図した結果になりません。 -- henoheno 2007-09-09 (日) 23:05:03
  • あ、通常(改造なし)の利用しか考えてませんでした。ということで、この部分は却下で。 -- 2007-09-09 (日) 23:25:59

[fixed] その他: 表示上限をマイナスで指定した時

  • 表示上限をマイナスで指定した時にメッセージがおかしくなります。
    例
    全50件中、上位-20件を表示しています。
    array_splice()は負の値にも対応しているので、リストには、(50 - 20) つまり30件が表示される
    表示上限としているので、負の値とした時に無効とするか、メッセージの側を対応させる必要があると思います。
    下は該当箇所周辺です。
    (中略)
    class Tracker_list
    {
    (中略)
    	function toString($limit=NULL)
    	{
    		global $_tracker_messages;
    
    		$source = array();
    		$body = array();
    
    		$count = count($this->rows);
    		if ($limit !== NULL && $count > $limit)
    		{
    			$source[] = str_replace(
    				array('$1',  '$2'),
    				array($count,$limit),
    				$_tracker_messages['msg_limit']) . "\n";
    			$this->rows = array_splice($this->rows,0,$limit);
    		}
    		if (empty($this->rows))
    		{
    			return '';
    		}
    (中略)
    		foreach ($this->rows as $row)
    		{
    			if (! TRACKER_LIST_SHOW_ERROR_PAGE && ! $row['_match'])
    			{
    				continue;
    			}
    (以降、略)
    表示上限が0 のときは、if (empty($this->rows)) が拾ってくれるので大丈夫だと思います。
    それとこの部分に関連して、「項目の取り出しに失敗したページを表示しない」としている時、
    まずこの部分で、ソートした後の$this->rows を表示上限まで減らしてから、取り出しの成否を調べているので、
    全50件中、上位20件を表示しています。
    となっていても、実際にはリストが20件でない可能性があります。 -- 2007-06-11 (月) 22:03:24
  • #tracker_list の引数「表示上限」にマイナスを入れると、「総数 - 指定した数」が表示された上で、メッセージが変になる様ですが、これは以前からあった症状みたいですね。 -- henoheno 2007-09-03 (月) 00:09:35
    • とりあえず現状、0とすると制限なしとして動作、0未満の値を入れると 1 と解釈して動作する様に直すまではやりました。 -- henoheno 2007-09-09 (日) 23:13:29


その他: ヘルプの記載と実際の動作の違いについて

  • ページのタイトルとは少し外れますが、最近ここを中心にCleanup 、その他をしているようなのでここに書き込みます*6
    tracker_list のヘルプには昇順固定、昇順(閲覧者が変更可)、降順固定、降順(閲覧者が変更可)のように、
    ヘッダ行やフッタ行に表示されるリンクの表示を制御できるかのように書いてありますが、
    今のバージョンだと例えば昇順固定にしていてもその項目に、降順に変更するためのリンクが表示されます。
    どちらにあわせて修正する方がいいのかがわからないのでとりあえず挙げます。 -- 2007-09-09 (日) 14:34:57
  • 追記ありがとうございます。編集認証の話とか色々あって、もうやらざるをえないかな、という事で一人合宿中です。 -- henoheno 2007-09-09 (日) 21:45:02
  • 「昇順固定」「降順固定」という脚注は見逃していました。ASCは単にSORT_ASCの短縮形だろうと思ってスルーしていました。今のコードに「固定」に関する部分はあったかしら? -- henoheno 2007-09-09 (日) 21:49:28
  • Tracker_list->sort() でASCをSORT_ASCにといった様に置き換えてソート、置き換えたオプションを基にTracker_list->replace_title() でリンクを付けているので、今のコードにはないのではと。フラグもなさそうですし。
    とはいえこの機能が正常に機能していても、plugin_tracker_list_action() を呼んだ後に、アドレスを書き換えれば回避できる程度の機能のはずですけど。 -- 2007-09-09 (日) 22:53:46
  • 今の Tracker_list::sort() は ASC と SORT_ASC を完全に同一視していて、いずれも array_multisort() の引数として有効な定数 "SORT_ASC" としてしか保存していません。固定なのか固定でないのかすら保存していないので、入れ物を作らねばならないでしょう。また、sort()のTODO:に書いた通り、なぜかsort条件の判定がstringで統一されていない(stringの世界であるのに、定数(=int)を許さないと一部まともに動かない)ので、それを直してからでないと着手できないでしょう。plugin_tracker_list_action() の部分は御意の通り、全く問題にならないでしょう。 -- henoheno 2007-09-09 (日) 23:12:03
  • tracker_list 周りのこの辺りの下地は大体直しましたが、周辺の状況がどうも腑に落ちません。誤解しているかもしれませんが、「ユーザーの操作を受け付けない(強制できる)」状態を仮にfix(fixed)と呼びましょう。(1)この状況を例えばFIXED_ASC、FIXED_DESCといった名称で示すならまだ解るのですが、ASC と SORT_ASC という「略語と正式名称」を想起させる関係にあてはめるというのは直感的でない(奥が深い)デザインであるように思います。(2)固定したい時って実際にはどんな時なのでしょう。ユーザーがURLをちょっといじれば解除できますが、それでもいいものなのでしょうか。よろしかったら身近な例で構いませんので教えて下さい。 -- henoheno 2007-09-18 (火) 23:58:12
    • ええと、あまりいい答えじゃない気がしますが。
      私がこの機能について疑問を抱いたのは、ぱんだ:tracker.inc.phpに設置されているTracker_list を見たからです。このページのリストにはリンクがついていなかったので、こんな事もできるんだと思ってヘルプを見て試してみたら、実際にはできなっかたのでこうして提示したのです。
      どの機能が先で、どれが後から追加されたかがあまりわかっていないので、(1)のソートタイプ名(の由来やその他)についてはお役に立てそうもありません。
      それで(2)の質問なのですが、今すぐぱっと思いつくのはBugTrack_list プラグインと同じような感じにするということしか、固定するニーズを思いつきませんでした。ヘッダやフッタは表示したいが、表示順を安易に変えたくないとか、リンクが無いほうがBugTrack_list っぽく見えるとか。でもそれだと項目ごとじゃなく、全項目一括でどうするかの方が楽な気がします。この例だと裏技(URL をいじる)をありとするかどうかは、設置者しだいということになります。
      参考になるか微妙なんですが、ひとまずこんなところで。もっといい例を思いつかねば。 -- 2007-09-19 (水) 00:51:04
    • 便利さを読み取れていないという点で同じ立場みたいですね (^^; テーブルのheaderにリンクをつけないだけなら、多分 :config/tracker/XXX/list をいじれば*7できます。 -- henoheno 2007-09-20 (木) 00:43:33
  • 別の場所でも触れましたが、ASC, DESC ともに、 SORT_ASC, SORT_DESC の短縮形として再定義した上、短いほう(の、小文字)をデフォルトにしました。 -- henoheno 2007-09-24 (月) 11:37:26
    • (少し話題からずれますが)tracker 系のヘルプの修正量がすごいことになりそうですね、定数の増加やその他で。まだ、仕様が固まっていないので手は出しませんが。 -- 2007-09-24 (月) 16:13:44
      • バージョンつながりから今気づいたので、ついでにメモ。2007年に更新したcvs:lib/init.php に記載のフッタに表示されるCopyright 表記。1.4.7_1_alpha と1.4.8_alphaはいまだに、「2001-2006 PukiWiki Developers Team」となっていますね。ぱっと見た目、最新の物が入っているのかが判らないんで、2001-2007 に直したほうがいいと思うんですけど(って今年の残りがあと3ヶ月になってから言っても意味無いかな)。 -- 2007-09-24 (月) 16:13:44

改行の扱い (tracker_listにおいて、表が崩れたり、意図しないWiki textが生成される原因)


コメント

  • その他にもざっくり手を入れました。まだ妙な部分はいろいろあるかと思います。なぜおかしいかを説明いただいているのでとても助かります :) ありがとうございます。-- henoheno 2007-06-10 (日) 22:08:09
    • cvs:plugin/tracker.inc.php (1.37) -- 何か妙なところがあれば、ご指摘下さい
    • (今回の修正では、体感上の速度は変わらないかも) -- henoheno 2007-06-10 (日) 22:10:24
    • なお、めったに使われていないかと思いますが、bugtrackプラグインの流れを組んでいるから実装されているのだろう 'move to' を追跡する機構について、tracker_list が想定していない移動先(tracker対象ページの外に移動したかのように見えて、移動していない)の時に表示が増えるバグを直したつもりです。 -- henoheno 2007-06-10 (日) 22:12:46
      [[tracker/1]], [[tracker/2]], ... という形でtrackerが展開されていたとき、
      [[tracker/3]] の中身が 'move to [[foobar]]' だったならば、tracker_list は
      [[tracker/3]] の代わりに [[foobar]] を表示する。しかし、[[tracker/3]] の
      中身が例えば 'move to [[tracker/4]]' だった時、tracker_list は [[tracker/4]]
      を二回表示してしまう。
      (移動先が tracker/ 以下でなければこのような挙動は起きない)
  • 他の方が見つけられたからageられたのであろう、tracker関係: BugTrack2/240 BugTrack2/125。ああ、ついにtrackerに手を出してしまったのだなあ。しみじみ・・・ -- henoheno 2007-06-11 (月) 23:07:09
  • 関連: BugTrack/599 tracker_listでブラケットがそのまま表示される -- 2007-09-20 (木) 21:35:52
  • (1.78) 記載の「TODO: Why not $pagename」について少しコメントを。
    もし今のままこの部分で$pagename を採用(代入)すると、ソート後の並び順は一覧(page_list())と同じようになってしまいます。 -- 2007-09-24 (月) 00:16:52
    もし今、$pagename を採用して'_real'だけでソートしたら...(並び順のイメージ)
    質問箱4/1
    質問箱4/10
    質問箱4/100
    質問箱4/101
    質問箱4/102
    質問箱4/103
    質問箱4/104
    質問箱4/105
    質問箱4/106
    質問箱4/107
    質問箱4/108
    質問箱4/109
    質問箱4/11
    質問箱4/110
    • 1,2,3,...と順番に並べることができるのはメリットだと思うのですが。 -- 2007-09-24 (月) 00:25:52
  • 解説つきのコメントをありがとうございます。ここで実現したい事は natural orderの sort (See natsort()) かもしれませんが、ここは natural order さえあれば不要な構造であるはずです。で、今、別件で懸案であった 汎用的な natural order (SORT_NATURAL ... という定数はPHPに無いが、それが動くようにした) を実装する所まで持ってくる事ができましたので、特に問題なければ、この _real に関する特別な処理/データ構造/etc は削ることができる・・・といいなぁ・・・と思います。むしろ理解しやすくなるので削らせて下さい。 -- henoheno 2007-09-24 (月) 12:57:16
    • cvs:plugin/tracker.inc.php (r1.82) -- 2007-09-24 (月) 13:02:29
    • (r1.85) で試しました。かなりいいですよね。ここから先は好みの問題なのですが、BugTrack2/108でも話題となっている「大文字小文字を区別しなければ同じだが区別すれば違うと判別される時の並び順」について。ページ名以外でも使うことになってもいいように、もし余裕があって実現可能であるのならば、全て大文字 → 全て小文字 の順に並んで行ってくれるとうれしいんですが。 -- 2007-09-24 (月) 15:49:12


補足

  • tracker, tracker_list 両プラグインから呼び出されるものの、
    cvs:plugin/tracker.inc.php (v 1.38) には特にコメントがないclass Tracker_field の内容について、
    蛇足な気はしますが、簡単に役割の説明を。
Tracker_field->Tracker_field()
plugin_tracker_get_fields() で、クラスのインスタンスを生成する時に、呼び出される。
Tracker_field->get_tag()
plugin_tracker_convert() が、入力フォームを形成するために、呼び出す。
Tracker_field->get_style()
Tracker_list->replace_item() が、リストの各項目に応じてテンプレートで設定したスタイルを適用するために、呼び出す。
例えば、defaultの[Status]で、提案のスタイルを適用すると、BGCOLOR(#ffccff):データとなる。
 単純に%s を各データに置き換えるだけなので、
表形式以外でこの機能を使うには、「&color(,#ffccff){%s};」のように設定する必要がある。
Tracker_field->format_value()
plugin_tracker_action() が、フォームから送信されたデータをページに書き込むデータに変換するために、呼び出す。
Tracker_field->format_cell()
Tracker_list->replace_item() が、ページに記録されたデータをリストに表示する形式に変換するために、呼び出す。
例えば、textarea のデータを表形式に対応させるため改行を削除する(表形式以外でもこの処理は固定ですけど)
例えば、[_update]等の日時データを人が読める形式にする
 など...
Tracker_field->get_value()
Tracker_list->sort() が、ソート専用の値を得るために、呼び出す。
例えば、defaultの[Status]は、提案は0番、着手は1番、...、却下は5番、これ以外は値そのまま、を数値的比較でソートする。
ただ、その他の値は、意図した順番(最初か最後)にならない可能性があります。
  • 今ソースに記載されている順と、実際の呼び出し順が違ったりしますがこんなところです。 -- 2007-06-11 (月) 21:28:20

test
TEST

*test&br;TEST
test
TEST
test
TEST
:test&br;TEST|test&br;TEST
test
TEST
test
TEST
|test&br;TEST|test&br;TEST|
test
TEST
test
TEST
,test&br;TEST,test&br;TEST
  • test
    TEST
-test&br;TEST

test
TEST

&size(22){test&br;TEST};

*1 ある程度コメント等がある(データ量のある)ページでないと...
*2 各ページのソースが5 Kバイトで400 ページある、としても約2 Mバイトですし、全項目をリスト化するわけでもないし
*3 デフォルトなら、:config/plugin/tracker/default
*4 リストのページで設定すれば表示できるが、表形式の場合、表示が崩れる可能性がある
*5 例えば、テストする時
*6 まとめページみたくなってきてる(汗)
*7 bracketで項目名を書き込むあの手法を止めれば

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2007-09-24 (月) 16:09:41
Site admin: PukiWiki Development Team

PukiWiki 1.5.2+ © 2001-2019 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u7. HTML convert time: 0.289 sec.

OSDN