OSDN Git Service

add chat ver1.0
authorcake_67 <cake_67@46fa8b77-3530-0410-9d82-d95c44d28aba>
Wed, 7 Oct 2009 00:56:13 +0000 (00:56 +0000)
committercake_67 <cake_67@46fa8b77-3530-0410-9d82-d95c44d28aba>
Wed, 7 Oct 2009 00:56:13 +0000 (00:56 +0000)
git-svn-id: svn+ssh://svn.sourceforge.jp/svnroot/trpgtools-onweb/src/trunk/AjaxChatForTRPG@7 46fa8b77-3530-0410-9d82-d95c44d28aba

40 files changed:
image/blog_jscript.gif [new file with mode: 0644]
image/comment_r_b.gif [new file with mode: 0644]
image/d1.gif [new file with mode: 0644]
image/d4.gif [new file with mode: 0644]
image/d6.gif [new file with mode: 0644]
image/file_pen_b.gif [new file with mode: 0644]
image/help_b.gif [new file with mode: 0644]
image/home_b.gif [new file with mode: 0644]
image/index.html [new file with mode: 0644]
image/item_move_left.gif [new file with mode: 0644]
image/item_move_right.gif [new file with mode: 0644]
image/key_normal.gif [new file with mode: 0644]
image/key_open.gif [new file with mode: 0644]
image/property_b.gif [new file with mode: 0644]
image/reload_b.gif [new file with mode: 0644]
image/whisper.gif [new file with mode: 0644]
index.css [new file with mode: 0644]
index.php [new file with mode: 0644]
lib/index.html [new file with mode: 0644]
lib/jquery.js [new file with mode: 0644]
lock.txt [new file with mode: 0644]
lock2.txt [new file with mode: 0644]
main.css [new file with mode: 0644]
main.php [new file with mode: 0644]
master_past/index.html [new file with mode: 0644]
member.log [new file with mode: 0644]
member_check.php [new file with mode: 0644]
past/index.html [new file with mode: 0644]
pastlog-ini.php [new file with mode: 0644]
pastlog.php [new file with mode: 0644]
pastlog_index.php [new file with mode: 0644]
pastlog_main.php [new file with mode: 0644]
trpgchat-ini.php [new file with mode: 0644]
trpgchat.css [new file with mode: 0644]
trpgchat.log [new file with mode: 0644]
trpgchat_past.log [new file with mode: 0644]
write.php [new file with mode: 0644]
ドキュメント/LICENSE.txt [new file with mode: 0644]
ドキュメント/README.txt [new file with mode: 0644]
ドキュメント/ライセンス.txt [new file with mode: 0644]

diff --git a/image/blog_jscript.gif b/image/blog_jscript.gif
new file mode 100644 (file)
index 0000000..223c805
Binary files /dev/null and b/image/blog_jscript.gif differ
diff --git a/image/comment_r_b.gif b/image/comment_r_b.gif
new file mode 100644 (file)
index 0000000..c0db988
Binary files /dev/null and b/image/comment_r_b.gif differ
diff --git a/image/d1.gif b/image/d1.gif
new file mode 100644 (file)
index 0000000..99e47b1
Binary files /dev/null and b/image/d1.gif differ
diff --git a/image/d4.gif b/image/d4.gif
new file mode 100644 (file)
index 0000000..7279521
Binary files /dev/null and b/image/d4.gif differ
diff --git a/image/d6.gif b/image/d6.gif
new file mode 100644 (file)
index 0000000..d5163f2
Binary files /dev/null and b/image/d6.gif differ
diff --git a/image/file_pen_b.gif b/image/file_pen_b.gif
new file mode 100644 (file)
index 0000000..6884fc3
Binary files /dev/null and b/image/file_pen_b.gif differ
diff --git a/image/help_b.gif b/image/help_b.gif
new file mode 100644 (file)
index 0000000..135959a
Binary files /dev/null and b/image/help_b.gif differ
diff --git a/image/home_b.gif b/image/home_b.gif
new file mode 100644 (file)
index 0000000..d174887
Binary files /dev/null and b/image/home_b.gif differ
diff --git a/image/index.html b/image/index.html
new file mode 100644 (file)
index 0000000..e7692e6
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\r
+<title>TRPGのためのAjaxチャット</title>\r
+</head>\r
+<body>\r
+\r
+TRPGのためのAjaxChat配布サイトは<a href="http://trpgtools-onweb.sourceforge.jp/">こちら。</a>\r
+\r
+</body>\r
+</html>\r
diff --git a/image/item_move_left.gif b/image/item_move_left.gif
new file mode 100644 (file)
index 0000000..f2f33a0
Binary files /dev/null and b/image/item_move_left.gif differ
diff --git a/image/item_move_right.gif b/image/item_move_right.gif
new file mode 100644 (file)
index 0000000..355af63
Binary files /dev/null and b/image/item_move_right.gif differ
diff --git a/image/key_normal.gif b/image/key_normal.gif
new file mode 100644 (file)
index 0000000..a65061c
Binary files /dev/null and b/image/key_normal.gif differ
diff --git a/image/key_open.gif b/image/key_open.gif
new file mode 100644 (file)
index 0000000..318ca95
Binary files /dev/null and b/image/key_open.gif differ
diff --git a/image/property_b.gif b/image/property_b.gif
new file mode 100644 (file)
index 0000000..8647c10
Binary files /dev/null and b/image/property_b.gif differ
diff --git a/image/reload_b.gif b/image/reload_b.gif
new file mode 100644 (file)
index 0000000..da87719
Binary files /dev/null and b/image/reload_b.gif differ
diff --git a/image/whisper.gif b/image/whisper.gif
new file mode 100644 (file)
index 0000000..cf21e81
Binary files /dev/null and b/image/whisper.gif differ
diff --git a/index.css b/index.css
new file mode 100644 (file)
index 0000000..3c85e7f
--- /dev/null
+++ b/index.css
@@ -0,0 +1,75 @@
+/* \94­\8c¾\98g\82Ì\90Ý\92è */\r
+@charset "Shift_JIS";\r
+\r
+/* \83\81\83C\83\93 */\r
+html {\r
+       font-weight: normal;\r
+}\r
+\r
+html {\r
+       margin: 5px;\r
+}\r
+\r
+body {\r
+       background: #EDEDED;\r
+       padding-top: 5px;\r
+       padding-left: 10px;\r
+       padding-right: 10px;\r
+       padding-bottom: 5px;\r
+}\r
+\r
+/* \83^\83O\95Ê */\r
+\r
+\r
+input[type="text"],input[type="password"],textarea {\r
+       padding: .1em .2em;\r
+       cursor: text;\r
+       overflow: auto;\r
+}\r
+\r
+input[type="radio"],\r
+input[type="checkbox"] {\r
+       margin-right: 5px;\r
+}\r
+\r
+button, input.btn {\r
+       text-align: center;\r
+       color: #222222;\r
+       background: #EDEDED;\r
+       border: outset 1px #b0b0b0;\r
+       padding: 0;\r
+       cursor: pointer;\r
+}\r
+\r
+/* \8cÂ\95Ê */\r
+.mainframe {\r
+       font-size: 12px;\r
+       color: #000000;\r
+       line-height: 2em;\r
+       border-width: 1px;\r
+       padding-top: 0px;\r
+       padding-left: 3px;\r
+       padding-right: 3px;\r
+       padding-bottom: 3px;\r
+}\r
+\r
+.chatform {\r
+    padding: 0px;\r
+}\r
+\r
+.online, nodisplay, online1, online2   {\r
+       display: none;\r
+}\r
+\r
+.mainframe {\r
+       max-width: 1024px;\r
+}\r
+\r
+.input_pc {\r
+       max-width: 1024px;\r
+       cursor:text;\r
+}\r
+\r
+.login_btn_area {\r
+       width: 35px;\r
+}
\ No newline at end of file
diff --git a/index.php b/index.php
new file mode 100644 (file)
index 0000000..9187019
--- /dev/null
+++ b/index.php
@@ -0,0 +1,523 @@
+<?php
+/*
+ * Ajax Chat for TRPG ver.1.0
+ * (c)2007 Cake All righ1ts reserved.
+ * Mail : cake_67@users.sourceforge.jp
+ * Home : http://trpgtools-onweb.sourceforge.jp/
+ *
+ * [注意事項他]
+ * 本チャットスクリプトの使用および配布は、BSDライセンスに基づきます。
+ * BSDライセンスの詳細につきましては、添付のライセンス.txtを参照してください。
+ *
+ * BSDライセンス概要&使用上の注意
+ * 1. このスクリプトはフリーソフトです。以下の条件を満たす限りにおいて、使用・改造・再配布(オリジナルおよび改造版の両方とも)は自由です。
+ * 再配布する場合、上記著作権表示、本条件書きおよび第2項・第3項の責任限定規定を必ず含めてください。
+ * 2. 同梱のアイコンはPetite Prier様(http://snow.if.tv/)の素材です。
+      本スクリプトの使用および再配布時にアイコンをそのまま用いる場合は、配布元の規定も遵守してください。
+ * 3. 本スクリプトは無保証です。自己責任で使用してください。このスクリプトを使用したいかなる損害に対しても、作者は一切の責任を負いません。
+ * 4. 設置および使用方法に関する質問は、配布サイトの掲示板にお願いします。ただし、必ず回答できるとは限りません。
+ * メールによる質問は、ご遠慮ください。
+ */
+
+// 設定ファイルの読み込み
+require_once 'trpgchat-ini.php';
+
+//カラーコード作成
+$color_list = array();
+foreach ($color_code as $k1 => $v1) {
+    foreach ($color_code as $v2) {
+        foreach ($color_code as $v3) {
+            $color_list[] = $v1.$v2.$v3;
+        }
+    }
+}
+array_unique($color_list);
+sort($color_list);
+
+// HTML出力
+print html_header('index', $title, true, true);
+ ?>
+
+<script type="text/javascript">
+<!--
+
+//変数の設定
+var getdata_on = <?php print $getdata_on; ?>*1000;
+var getdata_off = <?php print $getdata_off; ?>*1000;
+var noname = '<?php print $noname; ?>';
+var writescript = '<?php print $writescript; ?>';
+var now_member = '<?php print $now_member; ?>';
+var pc_num = '<?php print $pc_num; ?>';
+var pc_show = '<?php print $pc_show; ?>';
+var pc_hide = '<?php print $pc_hide; ?>';
+
+    //変換文字
+var target = new Array('\.');
+var change = new Array('.');
+
+// 起動時の処理
+$(function(){
+    //表示系
+        // ウィンドウサイズに合わせる
+    changeSize();//
+
+        // フォームON/OFF
+    document.getElementById("name_on").disabled = true;
+    document.getElementById("pwd_on").disabled = true;
+    document.getElementById("whisper_to").disabled = true;
+    $("#online1").hide();
+    $("#online2").hide();
+
+    //ログイン
+    $("#login").click(function(){
+
+        //入力チェック
+        var name = $("#name_off").attr("value");
+        if (!name || name == noname) {
+            alert("お名前を入力してください。");
+            return false;
+        }
+        //現在の入室者と同じ名前ではログインできない
+        if (isMember(name)==true) {
+            alert("現在の参加者と同じ名前ではログインできません。");
+            return false;
+        }
+
+        //データ整形
+        var params =
+            '?n='+convert(name)//名前
+            +'&s='+'0';//状態表示
+        if($("#pwd_off").attr("value")) {
+            var pwd = $("#pwd_off").attr("value");
+            if(pwd) {
+                var params =
+                params+'&p='+convert(pwd);//PWD
+            }
+        } else {
+            var pwd = "";
+        }
+        var params =
+            params+'&y=in'
+            +'&e='+(new Date()).getTime();//cacheの更新
+
+        writeComment(params);
+
+        //フォームチェンジ
+        $("#online1").show();
+        $("#online2").show();
+        $("#offline").hide();
+        document.getElementById("name_on").value = name;
+        document.getElementById("pc_name_0").value = name;
+        document.getElementById("pwd_on").value = pwd;
+        document.getElementById("pc_input_0").focus();
+
+        // 更新
+        window.mainframe.login();
+    });
+
+
+    //ログアウト
+    $("#logout").click(function(){
+
+        //データ整形
+        var name = convert($("#name_on").attr("value"));
+        var params =
+            '?n='+name//名前
+            +'&s='+'0'//状態表示
+        if($("#pwd_on").attr("value")) {
+            var params =
+            params
+            +'&p='+convert($("#pwd_on").attr("value"));//PWD
+        }
+        var params =
+            params+'&y=out'
+            +'&e='+(new Date()).getTime();//cacheの更新
+
+        writeComment(params);
+
+        //フォームチェンジ
+        $("#online1").hide();
+        $("#online2").hide();
+        $("#offline").show();
+        $(".status_column").hide();
+        $(".add_pc").hide();
+        $(".show_status").each(function(){
+            this.checked = false;
+        });
+//        for(i=1;i<=pc_num;i++) {
+//            document.getElementById("show_status").checked = false;
+//        }
+        document.getElementById("whisper_to").value = "全員";
+        document.getElementById("whisper_to_hash").value = "";
+        document.getElementById("pwd_on").value = "";
+        document.getElementById("my_hash").value = "";
+        document.getElementById("name_off").focus();
+
+        // タイマー更新
+        window.mainframe.logout();
+
+    });
+
+});
+
+
+// 発言
+function comment(Obj) {
+
+    // 発言取得
+    var pc_input = Obj.pc_input.value;
+    if (pc_input) {
+        //入力チェック
+        var name = convert($("#name_on").attr("value"));
+        var pc_name = Obj.pc_name.value;
+        if (!pc_name) {
+            alert("PC名を入力してください。");
+            return false;
+        }
+        var pc_color = Obj.pc_color.value;
+
+        //データ整形
+        var params =
+            '?n='+name//名前
+            +'&c='+convert(pc_name)//PC
+            +'&l='+pc_color//色
+            +'&m='+convert(pc_input);//本文
+
+        // ささやき
+        var whisper_to_name = $("#whisper_to").attr("value");
+        var whisper_to_hash = $("#whisper_to_hash").attr("value");
+        if(whisper_to_name && whisper_to_name != '全員' && whisper_to_hash) {
+            params = params
+                +'&w='+convert(whisper_to_name)//whisperto
+                +'&h='+whisper_to_hash;//whisperto_hash
+        }
+
+        //状態表示
+        if (Obj.show_status.checked) {
+            params = params+'&s='+'1';
+        } else {
+            params = params+'&s='+'0';
+        }
+
+        //状態
+        if (Obj.status.value) {
+            params = params+'&t='+convert(Obj.status.value);
+        }
+
+        //他
+//        params = params+'&a='+Obj.status.value;
+
+        if ($("#pwd_on").attr("value")) {
+            var pwd = convert($("#pwd_on").attr("value"));
+        }
+        if(pwd) {
+            var params =
+            params+'&p='+pwd;//PWD
+        }
+        var params =
+            params+'&y=com'
+            +'&e='+(new Date()).getTime();//cacheの更新
+
+        writeComment(params);
+
+        //フォームチェンジ
+        Obj.pc_input.value = "";
+    }
+        Obj.pc_input.focus();
+
+        return false;
+}
+
+
+// 書き込み
+function writeComment(params)
+{
+    $.ajax({
+        type: "GET",
+        url: writescript+params,
+        success: function() {
+    // 受信完了イベント
+            window.mainframe.getLog();
+        }
+    });
+}
+
+//禁止文字置換・エンコード
+function convert(C) {
+    for (var i=0; i < target.length; i++){
+//        C = C.replace(target[i], change[i]);
+        C = encodeURIComponent(C);
+    }
+    return C;
+}
+
+// 在室確認
+function isMember(name){
+    var member = $(window.mainframe.document.getElementById("indi")).text();
+    var name_array = member.split('<>');
+    for (i=0;i<name_array.length;i++) {
+        if (name_array[i] == name) {
+            return true;
+        }
+    }
+}
+
+// ダイスボタン
+function insertDice(Obj) {
+    var dice = $("#dice").attr("value");
+    var revision = $("#revision").attr("value");
+    if (typeof(revision) != 'string') {
+        revision = '0';
+    }
+
+    if (revision.match(/[^-0-9+\*\/]/)) {
+    alert(revision);
+        alert('ダイス修正値は半角数字と+,-,*,/のみで入力してください。');
+        return false;
+    }
+
+    var input = Obj.pc_input.value;
+
+    if (revision == '0') revision = "";
+
+    if (revision && !revision.match(/^[-+\*\/]/)) {
+        revision = '+'+revision;
+    }
+    Obj.pc_input.value = input+'['+dice+revision+']';
+    return false;
+}
+
+//セレクトボックスで選んだ画像色を取得
+function changeColor (Obj) {
+    Obj.style.color = Obj.value;
+}
+
+// 状態欄ON/OFF
+function toggleStatus(target) {
+    dispStatus = document.getElementById(target).style.display;
+    if (dispStatus == 'none') {
+        document.getElementById(target).style.display = '';
+    } else {
+        document.getElementById(target).style.display = 'none';
+    }
+}
+
+// PC欄ON
+function showPCcolumn(target) {
+    if (document.getElementById(target).style.display == 'none') {
+        document.getElementById(target).style.display = '';
+    }
+}
+
+// PC欄OFF
+function hidePCcolumn(target, status) {
+    if (document.getElementById(target).style.display != 'none') {
+        document.getElementById(target).style.display = 'none';
+        if (document.getElementById(status).style.display != 'none') {
+            document.getElementById(status).style.display = 'none'
+        }
+    }
+}
+
+// 入室中にリロード・ページ遷移で自動退室
+function UnLoad() {
+    var name = $("#name_on").attr("value");
+    if (name && isMember(name)==true) {
+        $("#logout").click();
+    }
+}
+
+// ウインドウサイズ変更でフォームサイズ変更
+function changeSize() {
+    var winWidth = document.body.clientWidth;
+    var winHeight = document.body.clientHeight - 105;
+    $(".input_comment").css({width: winWidth-300});
+    $(".status").css({width: winWidth-165});
+    $("#mainframe").css({height: winHeight});
+}
+
+// ホーム
+function returnHome() {
+    window.location.href="<?php print $home;?>";
+}
+
+//-->
+</script>
+</head>
+<body onresize="changeSize()" onunload="return UnLoad()">
+<table border="0" cellspacing="3" cellpadding="0" id="online1" class="online">
+<tr>
+<td class="nodisplay"><form id="chat_on" name="chat_on" onsubmit="return false;" action="" class="chatform"></td>
+<td><input type="text" name="name_on" value="" size="10" class="inputname" id="name_on"></td>
+<td><input type="password" name="pwd_on" size="4" class="inputpwd" id="pwd_on">
+<input type="hidden" name="my_hash" value="" id="my_hash"></td>
+<?php
+if ($preset_dice) {
+    print '<td align="right">';
+    print '<select name="dice" id="dice">'."\n";
+    foreach ($preset_dice as $v) {
+         print '<option value="'.$v.'">'.$v.'</option>'."\n";
+    }
+    print '</select></td>'."\n";
+    print '<td align="right"> + </td>'."\n";
+    print '<td align="right">';
+    print '<input type="text" size="6" value="" name="revision" id="revision" />';
+
+    print '</td>'."\n";
+}
+?>
+<td><span id="whisper_to_msg" style="display:inline;"> <img name="whisper" title="クリックで「ささやき」を解除します。" src="<?php print $whisper; ?>" alt="ささやき解除" align="bottom" hspace="1" vspace="0" border="0" onclick='document.getElementById("whisper_to").value="全員", document.getElementById("whisper_to_hash").value="", document.getElementById("whisper_mark").src="<?php print $whisper_off; ?>"'></td>
+<td><img id="whisper_mark" title="「ささやき」状態" src="<?php print $whisper_off; ?>" align="bottom" hspace="1" vspace="0" border="0"></span></td>
+<td><input type="text" name="whisper_to" value="全員" size="10" class="inputname" id="whisper_to" style="display:inline;">
+<input type="hidden" name="whisper_to_hash" value="" id="whisper_to_hash"></td>
+<td><input type="image" id="refresh" class="btn sub" src="<?php print $reload_icon; ?>" alt="リフレッシュ" title="リフレッシュ" onclick="window.mainframe.clearLog()"></td>
+<td align="right"><input type="button" value="退室" name="logout" class="btn logout" id="logout" /></td>
+<td class="nodisplay"></form></td>
+</tr>
+</table>
+<table border="0" cellspacing="3" cellpadding="0" id="online2" class="online">
+<tr>
+<td class="nodisplay"><form onsubmit="return false;" class="chatform"></td>
+<td align="left" nowrap><input type="text" name="pc_name" value="" size="10" class="inputname" id="pc_name_0">
+<select name="pc_color" class="color" onChange="changeColor(this)" style="font-weight: bold;">
+<?php colorbox($color_list, "pc_color", ""); ?>
+</select>
+<input type="text" name="pc_input" class="input_comment" id="pc_input_0" size="75%" /></td>
+<td><input type="submit" value="発言" class="btn sub" id="submit" style="display:inline" name="submit" onclick="comment(this.form)"></td>
+<?php
+    if ($dice_max) {
+        print '<td>';
+        print '<input type="image" id="dice" class="btn sub" src="'.$dice_icon.'" alt="ダイス" title="コメント欄にダイスを追加します。" onclick="insertDice(this.form);">';
+        print '</td>'."\n";
+    }
+?>
+<td><input type="image" class="btn sub" src="<?php print $status_icon; ?>" alt="状態" title="ステータス欄をON/OFFします。" onclick="toggleStatus('status_0');"></td>
+<?php
+if ($pc_num > 1) {
+   print '<td><input type="image" id="PC_btn_0" class="btn sub" src="'.$pc_show.'" alt="PC追加" title="PC欄を追加します。" onclick="showPCcolumn(\'pc_1\');"></td><td>&nbsp;</td>';
+}
+ ?>
+</tr>
+</table>
+<table border="0" cellspacing="3" cellpadding="0" id="status_0" class="status_column" style="display:none;">
+<tr>
+<td nowrap>ステータス:<input type="text" name="status" class="status" value="<?php print $status; ?>"></td>
+<td><input type="checkbox" name="show_status" class="show_status"></td>
+<td nowrap> 表示</td>
+<td class="nodisplay"></form></td>
+</tr>
+</table>
+
+<?php
+if ($pc_num >= 2) {
+    for ($i=1; $i<=$pc_num-1; $i++) {
+        print '<table border="0" cellspacing="3" cellpadding="0" id="pc_'.$i.'" class="add_pc" style="display:none;">'."\n";
+        print '<tr>'."\n";
+        print '<td class="nodisplay"><form onsubmit="return false;" class="chatform"></td>'."\n";
+        print '<td align="left" nowrap><input type="text" name="pc_name" value="" size="10" class="inputname">'."\n";
+        print '<select name="pc_color" class="color" onChange="changeColor(this)" style="font-weight: bold;">';
+colorbox($color_list, "pc_color", "");
+        print '</select>'."\n";
+        print '<input type="text" name="pc_input" class="input_comment" size="75%" />';
+        print '</td>'."\n";
+        print '<td><input type="submit" value="発言" class="btn sub" id="submit" style="display:inline" name="submit" onclick="comment(this.form)"></td>'."\n";
+        if ($dice_max) {
+            print '<td><input type="image" id="dice" class="btn sub" src="'.$dice_icon.'" alt="ダイス" title="コメント欄にダイスを追加します。" onclick="insertDice(this.form);"></td>'."\n";
+        }
+        print '<td><input type="image" class="btn sub" src="'.$status_icon.'" alt="状態" title="ステータス欄をON/OFFします。" onclick="toggleStatus(\'status_';
+        print $i;
+        print '\');"></td>'."\n";
+        print '<td width="20">';
+        if ($i != $pc_num-1) {
+            print '<input type="image" id="PC_btn_'.$i.'" class="btn sub" src="'.$pc_show.'" alt="PC欄" title="PC欄を追加します。" onclick="showPCcolumn(\'pc_';
+            print $i+1;
+            print '\');">';
+        } else {
+            print " ";
+        }
+        print '</td>'."\n";
+        print '<td><input type="image" id="PC_btn_'.$i.'" class="btn sub" src="'.$pc_hide.'" alt="PC欄" title="PC欄を削除します。" onclick="hidePCcolumn(\'pc_';
+        print $i;
+            print '\', \'status_';
+            print $i;
+        print '\');"></td>'."\n";
+        print '</tr>'."\n";
+        print '</table>'."\n";
+        print '<table border="0" cellspacing="3" cellpadding="0" id="status_'.$i.'" class="status_column" style="display:none;">'."\n";
+        print '<tr>'."\n";
+        print '<td nowrap>ステータス:<input type="text" name="status" class="status" value="'.$status.'"></td>'."\n";
+        print '<td><input name="show_status" type="checkbox" class="show_status"></td>'."\n";
+        print '<td nowrap> 表示</td>'."\n";
+        print '<td class="nodisplay"></form></td>'."\n";
+        print '</tr>'."\n";
+        print '</table>'."\n";
+    }
+}
+ ?>
+
+<table border="0" cellspacing="3" cellpadding="0" id="offline" style="display:inline;">
+<tr>
+<td class="nodisplay">
+<form id="chat_off" name="chat" onsubmit="return false;" action="" class="chatform">
+</td>
+<td nowrap>お名前
+<input type="text" name="name_off" value="<?php print $noname ?>" size="10" class="inputname" id="name_off">
+</td>
+<td nowrap>
+パスワード<input type="password" name="pwd_off" size="6" class="inputpwd" id="pwd_off">
+</td>
+<td id="login_btn_area" width="35">
+<input type="submit" value="入室" name="login" class="btn login" id="login" />
+</td>
+<td>
+<input type="image" id="reload" class="btn sub" src="<?php print $reload_icon; ?>" alt="リフレッシュ" title="リフレッシュ" onclick="window.mainframe.location.reload()">
+</td>
+<td class="nodisplay">
+</form>
+</td>
+<td class="nodisplay">
+<form action="<?php print $home; ?>">
+</td>
+<td>
+<input type="image" class="btn sub" src="<?php print $home_icon; ?>" value="submit" alt="ホーム" title="ホーム">
+</td>
+<td class="nodisplay">
+</form>
+</td>
+<td class="nodisplay">
+<form action="./pastlog_index.php" method="<?php print $method; ?>" target="pastlog">
+
+</td>
+<td>
+<input type="submit" value="過去ログ表示">
+
+</td>
+<td class="nodisplay">
+</form>
+</td>
+</tr>
+</table>
+
+<iframe src="./main.php" width="100%" frameborder="1" border="1" allowtransparency="true" scrolling="auto" name="mainframe" class="mainframe" style="height:500px;" id="mainframe"></iframe>
+
+<noscript>
+<p><img src="image/blog_jscript.gif" alt="Javascript" width="80" height="15">本チャットは、JavaScript が有効な環境でのみ使用可能です</p>
+</noscript>
+
+<?php
+
+// フッター
+print html_footer($copyright);
+
+
+//関数
+/* 名前色選択リスト生成 */
+function colorbox($colorlist, $id, $select=''){
+    foreach ($colorlist as $k => $v) {
+        print'<option value="'.$v.'" style="color: #'.$v.'; font-weight:bold;" id="'.$id.'_'.$v.'"';
+        if ($select == $v) { print ' selected';}
+        print ' >★</option>'."\n";
+    }
+}
+
+ ?>
\ No newline at end of file
diff --git a/lib/index.html b/lib/index.html
new file mode 100644 (file)
index 0000000..e7692e6
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\r
+<title>TRPGのためのAjaxチャット</title>\r
+</head>\r
+<body>\r
+\r
+TRPGのためのAjaxChat配布サイトは<a href="http://trpgtools-onweb.sourceforge.jp/">こちら。</a>\r
+\r
+</body>\r
+</html>\r
diff --git a/lib/jquery.js b/lib/jquery.js
new file mode 100644 (file)
index 0000000..a9f85f6
--- /dev/null
@@ -0,0 +1,2245 @@
+// /* prevent execution of jQuery if included more than once */\r
+if(typeof window.jQuery == "undefined") {\r
+/*\r
+ * jQuery 1.1.2 - New Wave Javascript\r
+ *\r
+ * Copyright (c) 2007 John Resig (jquery.com)\r
+ * Dual licensed under the MIT (MIT-LICENSE.txt)\r
+ * and GPL (GPL-LICENSE.txt) licenses.\r
+ *\r
+ * $Date: 2007-02-28 12:03:00 -0500 (Wed, 28 Feb 2007) $\r
+ * $Rev: 1465 $\r
+ */\r
+\r
+// Global undefined variable\r
+window.undefined = window.undefined;\r
+var jQuery = function(a,c) {\r
+       // If the context is global, return a new object\r
+       if ( window == this )\r
+               return new jQuery(a,c);\r
+\r
+       // Make sure that a selection was provided\r
+       a = a || document;\r
+\r
+       // HANDLE: $(function)\r
+       // Shortcut for document ready\r
+       if ( jQuery.isFunction(a) )\r
+               return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( a );\r
+\r
+       // Handle HTML strings\r
+       if ( typeof a  == "string" ) {\r
+               // HANDLE: $(html) -> $(array)\r
+               var m = /^[^<]*(<(.|\s)+>)[^>]*$/.exec(a);\r
+               if ( m )\r
+                       a = jQuery.clean( [ m[1] ] );\r
+\r
+               // HANDLE: $(expr)\r
+               else\r
+                       return new jQuery( c ).find( a );\r
+       }\r
+\r
+       return this.setArray(\r
+               // HANDLE: $(array)\r
+               a.constructor == Array && a ||\r
+\r
+               // HANDLE: $(arraylike)\r
+               // Watch for when an array-like object is passed as the selector\r
+               (a.jquery || a.length && a != window && !a.nodeType && a[0] != undefined && a[0].nodeType) && jQuery.makeArray( a ) ||\r
+\r
+               // HANDLE: $(*)\r
+               [ a ] );\r
+};\r
+\r
+// Map over the $ in case of overwrite\r
+if ( typeof $ != "undefined" )\r
+       jQuery._$ = $;\r
+\r
+// Map the jQuery namespace to the '$' one\r
+var $ = jQuery;\r
+\r
+jQuery.fn = jQuery.prototype = {\r
+       jquery: "1.1.2",\r
+\r
+       size: function() {\r
+               return this.length;\r
+       },\r
+\r
+       length: 0,\r
+\r
+       get: function( num ) {\r
+               return num == undefined ?\r
+\r
+                       // Return a 'clean' array\r
+                       jQuery.makeArray( this ) :\r
+\r
+                       // Return just the object\r
+                       this[num];\r
+       },\r
+       pushStack: function( a ) {\r
+               var ret = jQuery(a);\r
+               ret.prevObject = this;\r
+               return ret;\r
+       },\r
+       setArray: function( a ) {\r
+               this.length = 0;\r
+               [].push.apply( this, a );\r
+               return this;\r
+       },\r
+       each: function( fn, args ) {\r
+               return jQuery.each( this, fn, args );\r
+       },\r
+       index: function( obj ) {\r
+               var pos = -1;\r
+               this.each(function(i){\r
+                       if ( this == obj ) pos = i;\r
+               });\r
+               return pos;\r
+       },\r
+\r
+       attr: function( key, value, type ) {\r
+               var obj = key;\r
+\r
+               // Look for the case where we're accessing a style value\r
+               if ( key.constructor == String )\r
+                       if ( value == undefined )\r
+                               return this.length && jQuery[ type || "attr" ]( this[0], key ) || undefined;\r
+                       else {\r
+                               obj = {};\r
+                               obj[ key ] = value;\r
+                       }\r
+\r
+               // Check to see if we're setting style values\r
+               return this.each(function(index){\r
+                       // Set all the styles\r
+                       for ( var prop in obj )\r
+                               jQuery.attr(\r
+                                       type ? this.style : this,\r
+                                       prop, jQuery.prop(this, obj[prop], type, index, prop)\r
+                               );\r
+               });\r
+       },\r
+\r
+       css: function( key, value ) {\r
+               return this.attr( key, value, "curCSS" );\r
+       },\r
+\r
+       text: function(e) {\r
+               if ( typeof e == "string" )\r
+                       return this.empty().append( document.createTextNode( e ) );\r
+\r
+               var t = "";\r
+               jQuery.each( e || this, function(){\r
+                       jQuery.each( this.childNodes, function(){\r
+                               if ( this.nodeType != 8 )\r
+                                       t += this.nodeType != 1 ?\r
+                                               this.nodeValue : jQuery.fn.text([ this ]);\r
+                       });\r
+               });\r
+               return t;\r
+       },\r
+\r
+       wrap: function() {\r
+               // The elements to wrap the target around\r
+               var a = jQuery.clean(arguments);\r
+\r
+               // Wrap each of the matched elements individually\r
+               return this.each(function(){\r
+                       // Clone the structure that we're using to wrap\r
+                       var b = a[0].cloneNode(true);\r
+\r
+                       // Insert it before the element to be wrapped\r
+                       this.parentNode.insertBefore( b, this );\r
+\r
+                       // Find the deepest point in the wrap structure\r
+                       while ( b.firstChild )\r
+                               b = b.firstChild;\r
+\r
+                       // Move the matched element to within the wrap structure\r
+                       b.appendChild( this );\r
+               });\r
+       },\r
+       append: function() {\r
+               return this.domManip(arguments, true, 1, function(a){\r
+                       this.appendChild( a );\r
+               });\r
+       },\r
+       prepend: function() {\r
+               return this.domManip(arguments, true, -1, function(a){\r
+                       this.insertBefore( a, this.firstChild );\r
+               });\r
+       },\r
+       before: function() {\r
+               return this.domManip(arguments, false, 1, function(a){\r
+                       this.parentNode.insertBefore( a, this );\r
+               });\r
+       },\r
+       after: function() {\r
+               return this.domManip(arguments, false, -1, function(a){\r
+                       this.parentNode.insertBefore( a, this.nextSibling );\r
+               });\r
+       },\r
+       end: function() {\r
+               return this.prevObject || jQuery([]);\r
+       },\r
+       find: function(t) {\r
+               return this.pushStack( jQuery.map( this, function(a){\r
+                       return jQuery.find(t,a);\r
+               }), t );\r
+       },\r
+       clone: function(deep) {\r
+               return this.pushStack( jQuery.map( this, function(a){\r
+                       var a = a.cloneNode( deep != undefined ? deep : true );\r
+                       a.$events = null; // drop $events expando to avoid firing incorrect events\r
+                       return a;\r
+               }) );\r
+       },\r
+\r
+       filter: function(t) {\r
+               return this.pushStack(\r
+                       jQuery.isFunction( t ) &&\r
+                       jQuery.grep(this, function(el, index){\r
+                               return t.apply(el, [index])\r
+                       }) ||\r
+\r
+                       jQuery.multiFilter(t,this) );\r
+       },\r
+\r
+       not: function(t) {\r
+               return this.pushStack(\r
+                       t.constructor == String &&\r
+                       jQuery.multiFilter(t, this, true) ||\r
+\r
+                       jQuery.grep(this, function(a) {\r
+                               return ( t.constructor == Array || t.jquery )\r
+                                       ? jQuery.inArray( a, t ) < 0\r
+                                       : a != t;\r
+                       })\r
+               );\r
+       },\r
+\r
+       add: function(t) {\r
+               return this.pushStack( jQuery.merge(\r
+                       this.get(),\r
+                       t.constructor == String ?\r
+                               jQuery(t).get() :\r
+                               t.length != undefined && (!t.nodeName || t.nodeName == "FORM") ?\r
+                                       t : [t] )\r
+               );\r
+       },\r
+       is: function(expr) {\r
+               return expr ? jQuery.filter(expr,this).r.length > 0 : false;\r
+       },\r
+\r
+       val: function( val ) {\r
+               return val == undefined ?\r
+                       ( this.length ? this[0].value : null ) :\r
+                       this.attr( "value", val );\r
+       },\r
+\r
+       html: function( val ) {\r
+               return val == undefined ?\r
+                       ( this.length ? this[0].innerHTML : null ) :\r
+                       this.empty().append( val );\r
+       },\r
+       domManip: function(args, table, dir, fn){\r
+               var clone = this.length > 1;\r
+               var a = jQuery.clean(args);\r
+               if ( dir < 0 )\r
+                       a.reverse();\r
+\r
+               return this.each(function(){\r
+                       var obj = this;\r
+\r
+                       if ( table && jQuery.nodeName(this, "table") && jQuery.nodeName(a[0], "tr") )\r
+                               obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody"));\r
+\r
+                       jQuery.each( a, function(){\r
+                               fn.apply( obj, [ clone ? this.cloneNode(true) : this ] );\r
+                       });\r
+\r
+               });\r
+       }\r
+};\r
+\r
+jQuery.extend = jQuery.fn.extend = function() {\r
+       // copy reference to target object\r
+       var target = arguments[0],\r
+               a = 1;\r
+\r
+       // extend jQuery itself if only one argument is passed\r
+       if ( arguments.length == 1 ) {\r
+               target = this;\r
+               a = 0;\r
+       }\r
+       var prop;\r
+       while (prop = arguments[a++])\r
+               // Extend the base object\r
+               for ( var i in prop ) target[i] = prop[i];\r
+\r
+       // Return the modified object\r
+       return target;\r
+};\r
+\r
+jQuery.extend({\r
+       noConflict: function() {\r
+               if ( jQuery._$ )\r
+                       $ = jQuery._$;\r
+               return jQuery;\r
+       },\r
+\r
+       // This may seem like some crazy code, but trust me when I say that this\r
+       // is the only cross-browser way to do this. --John\r
+       isFunction: function( fn ) {\r
+               return !!fn && typeof fn != "string" && !fn.nodeName &&\r
+                       typeof fn[0] == "undefined" && /function/i.test( fn + "" );\r
+       },\r
+\r
+       // check if an element is in a XML document\r
+       isXMLDoc: function(elem) {\r
+               return elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;\r
+       },\r
+\r
+       nodeName: function( elem, name ) {\r
+               return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();\r
+       },\r
+       // args is for internal usage only\r
+       each: function( obj, fn, args ) {\r
+               if ( obj.length == undefined )\r
+                       for ( var i in obj )\r
+                               fn.apply( obj[i], args || [i, obj[i]] );\r
+               else\r
+                       for ( var i = 0, ol = obj.length; i < ol; i++ )\r
+                               if ( fn.apply( obj[i], args || [i, obj[i]] ) === false ) break;\r
+               return obj;\r
+       },\r
+\r
+       prop: function(elem, value, type, index, prop){\r
+                       // Handle executable functions\r
+                       if ( jQuery.isFunction( value ) )\r
+                               value = value.call( elem, [index] );\r
+\r
+                       // exclude the following css properties to add px\r
+                       var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i;\r
+\r
+                       // Handle passing in a number to a CSS property\r
+                       return value && value.constructor == Number && type == "curCSS" && !exclude.test(prop) ?\r
+                               value + "px" :\r
+                               value;\r
+       },\r
+\r
+       className: {\r
+               // internal only, use addClass("class")\r
+               add: function( elem, c ){\r
+                       jQuery.each( c.split(/\s+/), function(i, cur){\r
+                               if ( !jQuery.className.has( elem.className, cur ) )\r
+                                       elem.className += ( elem.className ? " " : "" ) + cur;\r
+                       });\r
+               },\r
+\r
+               // internal only, use removeClass("class")\r
+               remove: function( elem, c ){\r
+                       elem.className = c ?\r
+                               jQuery.grep( elem.className.split(/\s+/), function(cur){\r
+                                       return !jQuery.className.has( c, cur );\r
+                               }).join(" ") : "";\r
+               },\r
+\r
+               // internal only, use is(".class")\r
+               has: function( t, c ) {\r
+                       t = t.className || t;\r
+                       // escape regex characters\r
+                       c = c.replace(/([\.\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");\r
+                       return t && new RegExp("(^|\\s)" + c + "(\\s|$)").test( t );\r
+               }\r
+       },\r
+       swap: function(e,o,f) {\r
+               for ( var i in o ) {\r
+                       e.style["old"+i] = e.style[i];\r
+                       e.style[i] = o[i];\r
+               }\r
+               f.apply( e, [] );\r
+               for ( var i in o )\r
+                       e.style[i] = e.style["old"+i];\r
+       },\r
+\r
+       css: function(e,p) {\r
+               if ( p == "height" || p == "width" ) {\r
+                       var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"];\r
+\r
+                       jQuery.each( d, function(){\r
+                               old["padding" + this] = 0;\r
+                               old["border" + this + "Width"] = 0;\r
+                       });\r
+\r
+                       jQuery.swap( e, old, function() {\r
+                               if (jQuery.css(e,"display") != "none") {\r
+                                       oHeight = e.offsetHeight;\r
+                                       oWidth = e.offsetWidth;\r
+                               } else {\r
+                                       e = jQuery(e.cloneNode(true))\r
+                                               .find(":radio").removeAttr("checked").end()\r
+                                               .css({\r
+                                                       visibility: "hidden", position: "absolute", display: "block", right: "0", left: "0"\r
+                                               }).appendTo(e.parentNode)[0];\r
+\r
+                                       var parPos = jQuery.css(e.parentNode,"position");\r
+                                       if ( parPos == "" || parPos == "static" )\r
+                                               e.parentNode.style.position = "relative";\r
+\r
+                                       oHeight = e.clientHeight;\r
+                                       oWidth = e.clientWidth;\r
+\r
+                                       if ( parPos == "" || parPos == "static" )\r
+                                               e.parentNode.style.position = "static";\r
+\r
+                                       e.parentNode.removeChild(e);\r
+                               }\r
+                       });\r
+\r
+                       return p == "height" ? oHeight : oWidth;\r
+               }\r
+\r
+               return jQuery.curCSS( e, p );\r
+       },\r
+\r
+       curCSS: function(elem, prop, force) {\r
+               var ret;\r
+\r
+               if (prop == "opacity" && jQuery.browser.msie)\r
+                       return jQuery.attr(elem.style, "opacity");\r
+\r
+               if (prop == "float" || prop == "cssFloat")\r
+                   prop = jQuery.browser.msie ? "styleFloat" : "cssFloat";\r
+\r
+               if (!force && elem.style[prop])\r
+                       ret = elem.style[prop];\r
+\r
+               else if (document.defaultView && document.defaultView.getComputedStyle) {\r
+\r
+                       if (prop == "cssFloat" || prop == "styleFloat")\r
+                               prop = "float";\r
+\r
+                       prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase();\r
+                       var cur = document.defaultView.getComputedStyle(elem, null);\r
+\r
+                       if ( cur )\r
+                               ret = cur.getPropertyValue(prop);\r
+                       else if ( prop == "display" )\r
+                               ret = "none";\r
+                       else\r
+                               jQuery.swap(elem, { display: "block" }, function() {\r
+                                   var c = document.defaultView.getComputedStyle(this, "");\r
+                                   ret = c && c.getPropertyValue(prop) || "";\r
+                               });\r
+\r
+               } else if (elem.currentStyle) {\r
+\r
+                       var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();});\r
+                       ret = elem.currentStyle[prop] || elem.currentStyle[newProp];\r
+\r
+               }\r
+\r
+               return ret;\r
+       },\r
+\r
+       clean: function(a) {\r
+               var r = [];\r
+\r
+               jQuery.each( a, function(i,arg){\r
+                       if ( !arg ) return;\r
+\r
+                       if ( arg.constructor == Number )\r
+                               arg = arg.toString();\r
+\r
+                        // Convert html string into DOM nodes\r
+                       if ( typeof arg == "string" ) {\r
+                               // Trim whitespace, otherwise indexOf won't work as expected\r
+                               var s = jQuery.trim(arg), div = document.createElement("div"), tb = [];\r
+\r
+                               var wrap =\r
+                                        // option or optgroup\r
+                                       !s.indexOf("<opt") &&\r
+                                       [1, "<select>", "</select>"] ||\r
+\r
+                                       (!s.indexOf("<thead") || !s.indexOf("<tbody") || !s.indexOf("<tfoot")) &&\r
+                                       [1, "<table>", "</table>"] ||\r
+\r
+                                       !s.indexOf("<tr") &&\r
+                                       [2, "<table><tbody>", "</tbody></table>"] ||\r
+\r
+                                       // <thead> matched above\r
+                                       (!s.indexOf("<td") || !s.indexOf("<th")) &&\r
+                                       [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||\r
+\r
+                                       [0,"",""];\r
+\r
+                               // Go to html and back, then peel off extra wrappers\r
+                               div.innerHTML = wrap[1] + s + wrap[2];\r
+\r
+                               // Move to the right depth\r
+                               while ( wrap[0]-- )\r
+                                       div = div.firstChild;\r
+\r
+                               // Remove IE's autoinserted <tbody> from table fragments\r
+                               if ( jQuery.browser.msie ) {\r
+\r
+                                       // String was a <table>, *may* have spurious <tbody>\r
+                                       if ( !s.indexOf("<table") && s.indexOf("<tbody") < 0 )\r
+                                               tb = div.firstChild && div.firstChild.childNodes;\r
+\r
+                                       // String was a bare <thead> or <tfoot>\r
+                                       else if ( wrap[1] == "<table>" && s.indexOf("<tbody") < 0 )\r
+                                               tb = div.childNodes;\r
+\r
+                                       for ( var n = tb.length-1; n >= 0 ; --n )\r
+                                               if ( jQuery.nodeName(tb[n], "tbody") && !tb[n].childNodes.length )\r
+                                                       tb[n].parentNode.removeChild(tb[n]);\r
+\r
+                               }\r
+\r
+                               arg = [];\r
+                               for (var i=0, l=div.childNodes.length; i<l; i++)\r
+                                       arg.push(div.childNodes[i]);\r
+                       }\r
+\r
+                       if ( arg.length === 0 && !jQuery.nodeName(arg, "form") )\r
+                               return;\r
+\r
+                       if ( arg[0] == undefined || jQuery.nodeName(arg, "form") )\r
+                               r.push( arg );\r
+                       else\r
+                               r = jQuery.merge( r, arg );\r
+\r
+               });\r
+\r
+               return r;\r
+       },\r
+\r
+       attr: function(elem, name, value){\r
+               var fix = jQuery.isXMLDoc(elem) ? {} : {\r
+                       "for": "htmlFor",\r
+                       "class": "className",\r
+                       "float": jQuery.browser.msie ? "styleFloat" : "cssFloat",\r
+                       cssFloat: jQuery.browser.msie ? "styleFloat" : "cssFloat",\r
+                       innerHTML: "innerHTML",\r
+                       className: "className",\r
+                       value: "value",\r
+                       disabled: "disabled",\r
+                       checked: "checked",\r
+                       readonly: "readOnly",\r
+                       selected: "selected"\r
+               };\r
+\r
+               // IE actually uses filters for opacity ... elem is actually elem.style\r
+               if ( name == "opacity" && jQuery.browser.msie && value != undefined ) {\r
+                       // IE has trouble with opacity if it does not have layout\r
+                       // Force it by setting the zoom level\r
+                       elem.zoom = 1;\r
+\r
+                       // Set the alpha filter to set the opacity\r
+                       return elem.filter = elem.filter.replace(/alpha\([^\)]*\)/gi,"") +\r
+                               ( value == 1 ? "" : "alpha(opacity=" + value * 100 + ")" );\r
+\r
+               } else if ( name == "opacity" && jQuery.browser.msie )\r
+                       return elem.filter ?\r
+                               parseFloat( elem.filter.match(/alpha\(opacity=(.*)\)/)[1] ) / 100 : 1;\r
+\r
+               // Mozilla doesn't play well with opacity 1\r
+               if ( name == "opacity" && jQuery.browser.mozilla && value == 1 )\r
+                       value = 0.9999;\r
+\r
+\r
+               // Certain attributes only work when accessed via the old DOM 0 way\r
+               if ( fix[name] ) {\r
+                       if ( value != undefined ) elem[fix[name]] = value;\r
+                       return elem[fix[name]];\r
+\r
+               } else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName(elem, "form") && (name == "action" || name == "method") )\r
+                       return elem.getAttributeNode(name).nodeValue;\r
+\r
+               // IE elem.getAttribute passes even for style\r
+               else if ( elem.tagName ) {\r
+                       if ( value != undefined ) elem.setAttribute( name, value );\r
+                       if ( jQuery.browser.msie && /href|src/.test(name) && !jQuery.isXMLDoc(elem) )\r
+                               return elem.getAttribute( name, 2 );\r
+                       return elem.getAttribute( name );\r
+\r
+               // elem is actually elem.style ... set the style\r
+               } else {\r
+                       name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();});\r
+                       if ( value != undefined ) elem[name] = value;\r
+                       return elem[name];\r
+               }\r
+       },\r
+       trim: function(t){\r
+               return t.replace(/^\s+|\s+$/g, "");\r
+       },\r
+\r
+       makeArray: function( a ) {\r
+               var r = [];\r
+\r
+               if ( a.constructor != Array )\r
+                       for ( var i = 0, al = a.length; i < al; i++ )\r
+                               r.push( a[i] );\r
+               else\r
+                       r = a.slice( 0 );\r
+\r
+               return r;\r
+       },\r
+\r
+       inArray: function( b, a ) {\r
+               for ( var i = 0, al = a.length; i < al; i++ )\r
+                       if ( a[i] == b )\r
+                               return i;\r
+               return -1;\r
+       },\r
+       merge: function(first, second) {\r
+               var r = [].slice.call( first, 0 );\r
+\r
+               // Now check for duplicates between the two arrays\r
+               // and only add the unique items\r
+               for ( var i = 0, sl = second.length; i < sl; i++ )\r
+                       // Check for duplicates\r
+                       if ( jQuery.inArray( second[i], r ) == -1 )\r
+                               // The item is unique, add it\r
+                               first.push( second[i] );\r
+\r
+               return first;\r
+       },\r
+       grep: function(elems, fn, inv) {\r
+               // If a string is passed in for the function, make a function\r
+               // for it (a handy shortcut)\r
+               if ( typeof fn == "string" )\r
+                       fn = new Function("a","i","return " + fn);\r
+\r
+               var result = [];\r
+\r
+               // Go through the array, only saving the items\r
+               // that pass the validator function\r
+               for ( var i = 0, el = elems.length; i < el; i++ )\r
+                       if ( !inv && fn(elems[i],i) || inv && !fn(elems[i],i) )\r
+                               result.push( elems[i] );\r
+\r
+               return result;\r
+       },\r
+       map: function(elems, fn) {\r
+               // If a string is passed in for the function, make a function\r
+               // for it (a handy shortcut)\r
+               if ( typeof fn == "string" )\r
+                       fn = new Function("a","return " + fn);\r
+\r
+               var result = [], r = [];\r
+\r
+               // Go through the array, translating each of the items to their\r
+               // new value (or values).\r
+               for ( var i = 0, el = elems.length; i < el; i++ ) {\r
+                       var val = fn(elems[i],i);\r
+\r
+                       if ( val !== null && val != undefined ) {\r
+                               if ( val.constructor != Array ) val = [val];\r
+                               result = result.concat( val );\r
+                       }\r
+               }\r
+\r
+               var r = result.length ? [ result[0] ] : [];\r
+\r
+               check: for ( var i = 1, rl = result.length; i < rl; i++ ) {\r
+                       for ( var j = 0; j < i; j++ )\r
+                               if ( result[i] == r[j] )\r
+                                       continue check;\r
+\r
+                       r.push( result[i] );\r
+               }\r
+\r
+               return r;\r
+       }\r
+});\r
+\r
+/*\r
+ * Whether the W3C compliant box model is being used.\r
+ *\r
+ * @property\r
+ * @name $.boxModel\r
+ * @type Boolean\r
+ * @cat JavaScript\r
+ */\r
+new function() {\r
+       var b = navigator.userAgent.toLowerCase();\r
+\r
+       // Figure out what browser is being used\r
+       jQuery.browser = {\r
+               safari: /webkit/.test(b),\r
+               opera: /opera/.test(b),\r
+               msie: /msie/.test(b) && !/opera/.test(b),\r
+               mozilla: /mozilla/.test(b) && !/(compatible|webkit)/.test(b)\r
+       };\r
+\r
+       // Check to see if the W3C box model is being used\r
+       jQuery.boxModel = !jQuery.browser.msie || document.compatMode == "CSS1Compat";\r
+};\r
+\r
+jQuery.each({\r
+       parent: "a.parentNode",\r
+       parents: "jQuery.parents(a)",\r
+       next: "jQuery.nth(a,2,'nextSibling')",\r
+       prev: "jQuery.nth(a,2,'previousSibling')",\r
+       siblings: "jQuery.sibling(a.parentNode.firstChild,a)",\r
+       children: "jQuery.sibling(a.firstChild)"\r
+}, function(i,n){\r
+       jQuery.fn[ i ] = function(a) {\r
+               var ret = jQuery.map(this,n);\r
+               if ( a && typeof a == "string" )\r
+                       ret = jQuery.multiFilter(a,ret);\r
+               return this.pushStack( ret );\r
+       };\r
+});\r
+\r
+jQuery.each({\r
+       appendTo: "append",\r
+       prependTo: "prepend",\r
+       insertBefore: "before",\r
+       insertAfter: "after"\r
+}, function(i,n){\r
+       jQuery.fn[ i ] = function(){\r
+               var a = arguments;\r
+               return this.each(function(){\r
+                       for ( var j = 0, al = a.length; j < al; j++ )\r
+                               jQuery(a[j])[n]( this );\r
+               });\r
+       };\r
+});\r
+\r
+jQuery.each( {\r
+       removeAttr: function( key ) {\r
+               jQuery.attr( this, key, "" );\r
+               this.removeAttribute( key );\r
+       },\r
+       addClass: function(c){\r
+               jQuery.className.add(this,c);\r
+       },\r
+       removeClass: function(c){\r
+               jQuery.className.remove(this,c);\r
+       },\r
+       toggleClass: function( c ){\r
+               jQuery.className[ jQuery.className.has(this,c) ? "remove" : "add" ](this, c);\r
+       },\r
+       remove: function(a){\r
+               if ( !a || jQuery.filter( a, [this] ).r.length )\r
+                       this.parentNode.removeChild( this );\r
+       },\r
+       empty: function() {\r
+               while ( this.firstChild )\r
+                       this.removeChild( this.firstChild );\r
+       }\r
+}, function(i,n){\r
+       jQuery.fn[ i ] = function() {\r
+               return this.each( n, arguments );\r
+       };\r
+});\r
+\r
+jQuery.each( [ "eq", "lt", "gt", "contains" ], function(i,n){\r
+       jQuery.fn[ n ] = function(num,fn) {\r
+               return this.filter( ":" + n + "(" + num + ")", fn );\r
+       };\r
+});\r
+\r
+jQuery.each( [ "height", "width" ], function(i,n){\r
+       jQuery.fn[ n ] = function(h) {\r
+               return h == undefined ?\r
+                       ( this.length ? jQuery.css( this[0], n ) : null ) :\r
+                       this.css( n, h.constructor == String ? h : h + "px" );\r
+       };\r
+});\r
+jQuery.extend({\r
+       expr: {\r
+               "": "m[2]=='*'||jQuery.nodeName(a,m[2])",\r
+               "#": "a.getAttribute('id')==m[2]",\r
+               ":": {\r
+                       // Position Checks\r
+                       lt: "i<m[3]-0",\r
+                       gt: "i>m[3]-0",\r
+                       nth: "m[3]-0==i",\r
+                       eq: "m[3]-0==i",\r
+                       first: "i==0",\r
+                       last: "i==r.length-1",\r
+                       even: "i%2==0",\r
+                       odd: "i%2",\r
+\r
+                       // Child Checks\r
+                       "nth-child": "jQuery.nth(a.parentNode.firstChild,m[3],'nextSibling',a)==a",\r
+                       "first-child": "jQuery.nth(a.parentNode.firstChild,1,'nextSibling')==a",\r
+                       "last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a",\r
+                       "only-child": "jQuery.sibling(a.parentNode.firstChild).length==1",\r
+\r
+                       // Parent Checks\r
+                       parent: "a.firstChild",\r
+                       empty: "!a.firstChild",\r
+\r
+                       // Text Check\r
+                       contains: "jQuery.fn.text.apply([a]).indexOf(m[3])>=0",\r
+\r
+                       // Visibility\r
+                       visible: 'a.type!="hidden"&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden"',\r
+                       hidden: 'a.type=="hidden"||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden"',\r
+\r
+                       // Form attributes\r
+                       enabled: "!a.disabled",\r
+                       disabled: "a.disabled",\r
+                       checked: "a.checked",\r
+                       selected: "a.selected||jQuery.attr(a,'selected')",\r
+\r
+                       // Form elements\r
+                       text: "a.type=='text'",\r
+                       radio: "a.type=='radio'",\r
+                       checkbox: "a.type=='checkbox'",\r
+                       file: "a.type=='file'",\r
+                       password: "a.type=='password'",\r
+                       submit: "a.type=='submit'",\r
+                       image: "a.type=='image'",\r
+                       reset: "a.type=='reset'",\r
+                       button: 'a.type=="button"||jQuery.nodeName(a,"button")',\r
+                       input: "/input|select|textarea|button/i.test(a.nodeName)"\r
+               },\r
+               ".": "jQuery.className.has(a,m[2])",\r
+               "@": {\r
+                       "=": "z==m[4]",\r
+                       "!=": "z!=m[4]",\r
+                       "^=": "z&&!z.indexOf(m[4])",\r
+                       "$=": "z&&z.substr(z.length - m[4].length,m[4].length)==m[4]",\r
+                       "*=": "z&&z.indexOf(m[4])>=0",\r
+                       "": "z",\r
+                       _resort: function(m){\r
+                               return ["", m[1], m[3], m[2], m[5]];\r
+                       },\r
+                       _prefix: "z=a[m[3]];if(!z||/href|src/.test(m[3]))z=jQuery.attr(a,m[3]);"\r
+               },\r
+               "[": "jQuery.find(m[2],a).length"\r
+       },\r
+\r
+       // The regular expressions that power the parsing engine\r
+       parse: [\r
+               // Match: [@value='test'], [@foo]\r
+               /^\[ *(@)([a-z0-9_-]*) *([!*$^=]*) *('?"?)(.*?)\4 *\]/i,\r
+\r
+               // Match: [div], [div p]\r
+               /^(\[)\s*(.*?(\[.*?\])?[^[]*?)\s*\]/,\r
+\r
+               // Match: :contains('foo')\r
+               /^(:)([a-z0-9_-]*)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/i,\r
+\r
+               // Match: :even, :last-chlid\r
+               /^([:.#]*)([a-z0-9_*-]*)/i\r
+       ],\r
+\r
+       token: [\r
+               /^(\/?\.\.)/, "a.parentNode",\r
+               /^(>|\/)/, "jQuery.sibling(a.firstChild)",\r
+               /^(\+)/, "jQuery.nth(a,2,'nextSibling')",\r
+               /^(~)/, function(a){\r
+                       var s = jQuery.sibling(a.parentNode.firstChild);\r
+                       return s.slice(jQuery.inArray(a,s) + 1);\r
+               }\r
+       ],\r
+\r
+       multiFilter: function( expr, elems, not ) {\r
+               var old, cur = [];\r
+\r
+               while ( expr && expr != old ) {\r
+                       old = expr;\r
+                       var f = jQuery.filter( expr, elems, not );\r
+                       expr = f.t.replace(/^\s*,\s*/, "" );\r
+                       cur = not ? elems = f.r : jQuery.merge( cur, f.r );\r
+               }\r
+\r
+               return cur;\r
+       },\r
+       find: function( t, context ) {\r
+               // Quickly handle non-string expressions\r
+               if ( typeof t != "string" )\r
+                       return [ t ];\r
+\r
+               // Make sure that the context is a DOM Element\r
+               if ( context && !context.nodeType )\r
+                       context = null;\r
+\r
+               // Set the correct context (if none is provided)\r
+               context = context || document;\r
+\r
+               // Handle the common XPath // expression\r
+               if ( !t.indexOf("//") ) {\r
+                       context = context.documentElement;\r
+                       t = t.substr(2,t.length);\r
+\r
+               // And the / root expression\r
+               } else if ( !t.indexOf("/") ) {\r
+                       context = context.documentElement;\r
+                       t = t.substr(1,t.length);\r
+                       if ( t.indexOf("/") >= 1 )\r
+                               t = t.substr(t.indexOf("/"),t.length);\r
+               }\r
+\r
+               // Initialize the search\r
+               var ret = [context], done = [], last = null;\r
+\r
+               // Continue while a selector expression exists, and while\r
+               // we're no longer looping upon ourselves\r
+               while ( t && last != t ) {\r
+                       var r = [];\r
+                       last = t;\r
+\r
+                       t = jQuery.trim(t).replace( /^\/\//i, "" );\r
+\r
+                       var foundToken = false;\r
+\r
+                       // An attempt at speeding up child selectors that\r
+                       // point to a specific element tag\r
+                       var re = /^[\/>]\s*([a-z0-9*-]+)/i;\r
+                       var m = re.exec(t);\r
+\r
+                       if ( m ) {\r
+                               // Perform our own iteration and filter\r
+                               jQuery.each( ret, function(){\r
+                                       for ( var c = this.firstChild; c; c = c.nextSibling )\r
+                                               if ( c.nodeType == 1 && ( jQuery.nodeName(c, m[1]) || m[1] == "*" ) )\r
+                                                       r.push( c );\r
+                               });\r
+\r
+                               ret = r;\r
+                               t = t.replace( re, "" );\r
+                               if ( t.indexOf(" ") == 0 ) continue;\r
+                               foundToken = true;\r
+                       } else {\r
+                               // Look for pre-defined expression tokens\r
+                               for ( var i = 0; i < jQuery.token.length; i += 2 ) {\r
+                                       // Attempt to match each, individual, token in\r
+                                       // the specified order\r
+                                       var re = jQuery.token[i];\r
+                                       var m = re.exec(t);\r
+\r
+                                       // If the token match was found\r
+                                       if ( m ) {\r
+                                               // Map it against the token's handler\r
+                                               r = ret = jQuery.map( ret, jQuery.isFunction( jQuery.token[i+1] ) ?\r
+                                                       jQuery.token[i+1] :\r
+                                                       function(a){ return eval(jQuery.token[i+1]); });\r
+\r
+                                               // And remove the token\r
+                                               t = jQuery.trim( t.replace( re, "" ) );\r
+                                               foundToken = true;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       // See if there's still an expression, and that we haven't already\r
+                       // matched a token\r
+                       if ( t && !foundToken ) {\r
+                               // Handle multiple expressions\r
+                               if ( !t.indexOf(",") ) {\r
+                                       // Clean the result set\r
+                                       if ( ret[0] == context ) ret.shift();\r
+\r
+                                       // Merge the result sets\r
+                                       jQuery.merge( done, ret );\r
+\r
+                                       // Reset the context\r
+                                       r = ret = [context];\r
+\r
+                                       // Touch up the selector string\r
+                                       t = " " + t.substr(1,t.length);\r
+\r
+                               } else {\r
+                                       // Optomize for the case nodeName#idName\r
+                                       var re2 = /^([a-z0-9_-]+)(#)([a-z0-9\\*_-]*)/i;\r
+                                       var m = re2.exec(t);\r
+\r
+                                       // Re-organize the results, so that they're consistent\r
+                                       if ( m ) {\r
+                                          m = [ 0, m[2], m[3], m[1] ];\r
+\r
+                                       } else {\r
+                                               // Otherwise, do a traditional filter check for\r
+                                               // ID, class, and element selectors\r
+                                               re2 = /^([#.]?)([a-z0-9\\*_-]*)/i;\r
+                                               m = re2.exec(t);\r
+                                       }\r
+\r
+                                       // Try to do a global search by ID, where we can\r
+                                       if ( m[1] == "#" && ret[ret.length-1].getElementById ) {\r
+                                               // Optimization for HTML document case\r
+                                               var oid = ret[ret.length-1].getElementById(m[2]);\r
+\r
+                                               // Do a quick check for the existence of the actual ID attribute\r
+                                               // to avoid selecting by the name attribute in IE\r
+                                               if ( jQuery.browser.msie && oid && oid.id != m[2] )\r
+                                                       oid = jQuery('[@id="'+m[2]+'"]', ret[ret.length-1])[0];\r
+\r
+                                               // Do a quick check for node name (where applicable) so\r
+                                               // that div#foo searches will be really fast\r
+                                               ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];\r
+\r
+                                       } else {\r
+                                               // Pre-compile a regular expression to handle class searches\r
+                                               if ( m[1] == "." )\r
+                                                       var rec = new RegExp("(^|\\s)" + m[2] + "(\\s|$)");\r
+\r
+                                               // We need to find all descendant elements, it is more\r
+                                               // efficient to use getAll() when we are already further down\r
+                                               // the tree - we try to recognize that here\r
+                                               jQuery.each( ret, function(){\r
+                                                       // Grab the tag name being searched for\r
+                                                       var tag = m[1] != "" || m[0] == "" ? "*" : m[2];\r
+\r
+                                                       // Handle IE7 being really dumb about <object>s\r
+                                                       if ( jQuery.nodeName(this, "object") && tag == "*" )\r
+                                                               tag = "param";\r
+\r
+                                                       jQuery.merge( r,\r
+                                                               m[1] != "" && ret.length != 1 ?\r
+                                                                       jQuery.getAll( this, [], m[1], m[2], rec ) :\r
+                                                                       this.getElementsByTagName( tag )\r
+                                                       );\r
+                                               });\r
+\r
+                                               // It's faster to filter by class and be done with it\r
+                                               if ( m[1] == "." && ret.length == 1 )\r
+                                                       r = jQuery.grep( r, function(e) {\r
+                                                               return rec.test(e.className);\r
+                                                       });\r
+\r
+                                               // Same with ID filtering\r
+                                               if ( m[1] == "#" && ret.length == 1 ) {\r
+                                                       // Remember, then wipe out, the result set\r
+                                                       var tmp = r;\r
+                                                       r = [];\r
+\r
+                                                       // Then try to find the element with the ID\r
+                                                       jQuery.each( tmp, function(){\r
+                                                               if ( this.getAttribute("id") == m[2] ) {\r
+                                                                       r = [ this ];\r
+                                                                       return false;\r
+                                                               }\r
+                                                       });\r
+                                               }\r
+\r
+                                               ret = r;\r
+                                       }\r
+\r
+                                       t = t.replace( re2, "" );\r
+                               }\r
+\r
+                       }\r
+\r
+                       // If a selector string still exists\r
+                       if ( t ) {\r
+                               // Attempt to filter it\r
+                               var val = jQuery.filter(t,r);\r
+                               ret = r = val.r;\r
+                               t = jQuery.trim(val.t);\r
+                       }\r
+               }\r
+\r
+               // Remove the root context\r
+               if ( ret && ret[0] == context ) ret.shift();\r
+\r
+               // And combine the results\r
+               jQuery.merge( done, ret );\r
+\r
+               return done;\r
+       },\r
+\r
+       filter: function(t,r,not) {\r
+               // Look for common filter expressions\r
+               while ( t && /^[a-z[({<*:.#]/i.test(t) ) {\r
+\r
+                       var p = jQuery.parse, m;\r
+\r
+                       jQuery.each( p, function(i,re){\r
+\r
+                               // Look for, and replace, string-like sequences\r
+                               // and finally build a regexp out of it\r
+                               m = re.exec( t );\r
+\r
+                               if ( m ) {\r
+                                       // Remove what we just matched\r
+                                       t = t.substring( m[0].length );\r
+\r
+                                       // Re-organize the first match\r
+                                       if ( jQuery.expr[ m[1] ]._resort )\r
+                                               m = jQuery.expr[ m[1] ]._resort( m );\r
+\r
+                                       return false;\r
+                               }\r
+                       });\r
+\r
+                       // :not() is a special case that can be optimized by\r
+                       // keeping it out of the expression list\r
+                       if ( m[1] == ":" && m[2] == "not" )\r
+                               r = jQuery.filter(m[3], r, true).r;\r
+\r
+                       // Handle classes as a special case (this will help to\r
+                       // improve the speed, as the regexp will only be compiled once)\r
+                       else if ( m[1] == "." ) {\r
+\r
+                               var re = new RegExp("(^|\\s)" + m[2] + "(\\s|$)");\r
+                               r = jQuery.grep( r, function(e){\r
+                                       return re.test(e.className || "");\r
+                               }, not);\r
+\r
+                       // Otherwise, find the expression to execute\r
+                       } else {\r
+                               var f = jQuery.expr[m[1]];\r
+                               if ( typeof f != "string" )\r
+                                       f = jQuery.expr[m[1]][m[2]];\r
+\r
+                               // Build a custom macro to enclose it\r
+                               eval("f = function(a,i){" +\r
+                                       ( jQuery.expr[ m[1] ]._prefix || "" ) +\r
+                                       "return " + f + "}");\r
+\r
+                               // Execute it against the current filter\r
+                               r = jQuery.grep( r, f, not );\r
+                       }\r
+               }\r
+\r
+               // Return an array of filtered elements (r)\r
+               // and the modified expression string (t)\r
+               return { r: r, t: t };\r
+       },\r
+\r
+       getAll: function( o, r, token, name, re ) {\r
+               for ( var s = o.firstChild; s; s = s.nextSibling )\r
+                       if ( s.nodeType == 1 ) {\r
+                               var add = true;\r
+\r
+                               if ( token == "." )\r
+                                       add = s.className && re.test(s.className);\r
+                               else if ( token == "#" )\r
+                                       add = s.getAttribute("id") == name;\r
+\r
+                               if ( add )\r
+                                       r.push( s );\r
+\r
+                               if ( token == "#" && r.length ) break;\r
+\r
+                               if ( s.firstChild )\r
+                                       jQuery.getAll( s, r, token, name, re );\r
+                       }\r
+\r
+               return r;\r
+       },\r
+       parents: function( elem ){\r
+               var matched = [];\r
+               var cur = elem.parentNode;\r
+               while ( cur && cur != document ) {\r
+                       matched.push( cur );\r
+                       cur = cur.parentNode;\r
+               }\r
+               return matched;\r
+       },\r
+       nth: function(cur,result,dir,elem){\r
+               result = result || 1;\r
+               var num = 0;\r
+               for ( ; cur; cur = cur[dir] ) {\r
+                       if ( cur.nodeType == 1 ) num++;\r
+                       if ( num == result || result == "even" && num % 2 == 0 && num > 1 && cur == elem ||\r
+                               result == "odd" && num % 2 == 1 && cur == elem ) return cur;\r
+               }\r
+       },\r
+       sibling: function( n, elem ) {\r
+               var r = [];\r
+\r
+               for ( ; n; n = n.nextSibling ) {\r
+                       if ( n.nodeType == 1 && (!elem || n != elem) )\r
+                               r.push( n );\r
+               }\r
+\r
+               return r;\r
+       }\r
+});\r
+/*\r
+ * A number of helper functions used for managing events.\r
+ * Many of the ideas behind this code orignated from\r
+ * Dean Edwards' addEvent library.\r
+ */\r
+jQuery.event = {\r
+\r
+       // Bind an event to an element\r
+       // Original by Dean Edwards\r
+       add: function(element, type, handler, data) {\r
+               // For whatever reason, IE has trouble passing the window object\r
+               // around, causing it to be cloned in the process\r
+               if ( jQuery.browser.msie && element.setInterval != undefined )\r
+                       element = window;\r
+\r
+               // if data is passed, bind to handler\r
+               if( data )\r
+                       handler.data = data;\r
+\r
+               // Make sure that the function being executed has a unique ID\r
+               if ( !handler.guid )\r
+                       handler.guid = this.guid++;\r
+\r
+               // Init the element's event structure\r
+               if (!element.$events)\r
+                       element.$events = {};\r
+\r
+               // Get the current list of functions bound to this event\r
+               var handlers = element.$events[type];\r
+\r
+               // If it hasn't been initialized yet\r
+               if (!handlers) {\r
+                       // Init the event handler queue\r
+                       handlers = element.$events[type] = {};\r
+\r
+                       // Remember an existing handler, if it's already there\r
+                       if (element["on" + type])\r
+                               handlers[0] = element["on" + type];\r
+               }\r
+\r
+               // Add the function to the element's handler list\r
+               handlers[handler.guid] = handler;\r
+\r
+               // And bind the global event handler to the element\r
+               element["on" + type] = this.handle;\r
+\r
+               // Remember the function in a global list (for triggering)\r
+               if (!this.global[type])\r
+                       this.global[type] = [];\r
+               this.global[type].push( element );\r
+       },\r
+\r
+       guid: 1,\r
+       global: {},\r
+\r
+       // Detach an event or set of events from an element\r
+       remove: function(element, type, handler) {\r
+               if (element.$events) {\r
+                       var i,j,k;\r
+                       if ( type && type.type ) { // type is actually an event object here\r
+                               handler = type.handler;\r
+                               type    = type.type;\r
+                       }\r
+\r
+                       if (type && element.$events[type])\r
+                               // remove the given handler for the given type\r
+                               if ( handler )\r
+                                       delete element.$events[type][handler.guid];\r
+\r
+                               // remove all handlers for the given type\r
+                               else\r
+                                       for ( i in element.$events[type] )\r
+                                               delete element.$events[type][i];\r
+\r
+                       // remove all handlers\r
+                       else\r
+                               for ( j in element.$events )\r
+                                       this.remove( element, j );\r
+\r
+                       // remove event handler if no more handlers exist\r
+                       for ( k in element.$events[type] )\r
+                               if (k) {\r
+                                       k = true;\r
+                                       break;\r
+                               }\r
+                       if (!k) element["on" + type] = null;\r
+               }\r
+       },\r
+\r
+       trigger: function(type, data, element) {\r
+               // Clone the incoming data, if any\r
+               data = jQuery.makeArray(data || []);\r
+\r
+               // Handle a global trigger\r
+               if ( !element )\r
+                       jQuery.each( this.global[type] || [], function(){\r
+                               jQuery.event.trigger( type, data, this );\r
+                       });\r
+\r
+               // Handle triggering a single element\r
+               else {\r
+                       var handler = element["on" + type ], val,\r
+                               fn = jQuery.isFunction( element[ type ] );\r
+\r
+                       if ( handler ) {\r
+                               // Pass along a fake event\r
+                               data.unshift( this.fix({ type: type, target: element }) );\r
+\r
+                               // Trigger the event\r
+                               if ( (val = handler.apply( element, data )) !== false )\r
+                                       this.triggered = true;\r
+                       }\r
+\r
+                       if ( fn && val !== false )\r
+                               element[ type ]();\r
+\r
+                       this.triggered = false;\r
+               }\r
+       },\r
+\r
+       handle: function(event) {\r
+               // Handle the second event of a trigger and when\r
+               // an event is called after a page has unloaded\r
+               if ( typeof jQuery == "undefined" || jQuery.event.triggered ) return;\r
+\r
+               // Empty object is for triggered events with no data\r
+               event = jQuery.event.fix( event || window.event || {} );\r
+\r
+               // returned undefined or false\r
+               var returnValue;\r
+\r
+               var c = this.$events[event.type];\r
+\r
+               var args = [].slice.call( arguments, 1 );\r
+               args.unshift( event );\r
+\r
+               for ( var j in c ) {\r
+                       // Pass in a reference to the handler function itself\r
+                       // So that we can later remove it\r
+                       args[0].handler = c[j];\r
+                       args[0].data = c[j].data;\r
+\r
+                       if ( c[j].apply( this, args ) === false ) {\r
+                               event.preventDefault();\r
+                               event.stopPropagation();\r
+                               returnValue = false;\r
+                       }\r
+               }\r
+\r
+               // Clean up added properties in IE to prevent memory leak\r
+               if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = event.handler = event.data = null;\r
+\r
+               return returnValue;\r
+       },\r
+\r
+       fix: function(event) {\r
+               // Fix target property, if necessary\r
+               if ( !event.target && event.srcElement )\r
+                       event.target = event.srcElement;\r
+\r
+               // Calculate pageX/Y if missing and clientX/Y available\r
+               if ( event.pageX == undefined && event.clientX != undefined ) {\r
+                       var e = document.documentElement, b = document.body;\r
+                       event.pageX = event.clientX + (e.scrollLeft || b.scrollLeft);\r
+                       event.pageY = event.clientY + (e.scrollTop || b.scrollTop);\r
+               }\r
+\r
+               // check if target is a textnode (safari)\r
+               if (jQuery.browser.safari && event.target.nodeType == 3) {\r
+                       // store a copy of the original event object\r
+                       // and clone because target is read only\r
+                       var originalEvent = event;\r
+                       event = jQuery.extend({}, originalEvent);\r
+\r
+                       // get parentnode from textnode\r
+                       event.target = originalEvent.target.parentNode;\r
+\r
+                       // add preventDefault and stopPropagation since\r
+                       // they will not work on the clone\r
+                       event.preventDefault = function() {\r
+                               return originalEvent.preventDefault();\r
+                       };\r
+                       event.stopPropagation = function() {\r
+                               return originalEvent.stopPropagation();\r
+                       };\r
+               }\r
+\r
+               // fix preventDefault and stopPropagation\r
+               if (!event.preventDefault)\r
+                       event.preventDefault = function() {\r
+                               this.returnValue = false;\r
+                       };\r
+\r
+               if (!event.stopPropagation)\r
+                       event.stopPropagation = function() {\r
+                               this.cancelBubble = true;\r
+                       };\r
+\r
+               return event;\r
+       }\r
+};\r
+\r
+jQuery.fn.extend({\r
+       bind: function( type, data, fn ) {\r
+               return this.each(function(){\r
+                       jQuery.event.add( this, type, fn || data, data );\r
+               });\r
+       },\r
+       one: function( type, data, fn ) {\r
+               return this.each(function(){\r
+                       jQuery.event.add( this, type, function(event) {\r
+                               jQuery(this).unbind(event);\r
+                               return (fn || data).apply( this, arguments);\r
+                       }, data);\r
+               });\r
+       },\r
+       unbind: function( type, fn ) {\r
+               return this.each(function(){\r
+                       jQuery.event.remove( this, type, fn );\r
+               });\r
+       },\r
+       trigger: function( type, data ) {\r
+               return this.each(function(){\r
+                       jQuery.event.trigger( type, data, this );\r
+               });\r
+       },\r
+       toggle: function() {\r
+               // Save reference to arguments for access in closure\r
+               var a = arguments;\r
+\r
+               return this.click(function(e) {\r
+                       // Figure out which function to execute\r
+                       this.lastToggle = this.lastToggle == 0 ? 1 : 0;\r
+\r
+                       // Make sure that clicks stop\r
+                       e.preventDefault();\r
+\r
+                       // and execute the function\r
+                       return a[this.lastToggle].apply( this, [e] ) || false;\r
+               });\r
+       },\r
+       hover: function(f,g) {\r
+\r
+               // A private function for handling mouse 'hovering'\r
+               function handleHover(e) {\r
+                       // Check if mouse(over|out) are still within the same parent element\r
+                       var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;\r
+\r
+                       // Traverse up the tree\r
+                       while ( p && p != this ) try { p = p.parentNode } catch(e) { p = this; };\r
+\r
+                       // If we actually just moused on to a sub-element, ignore it\r
+                       if ( p == this ) return false;\r
+\r
+                       // Execute the right function\r
+                       return (e.type == "mouseover" ? f : g).apply(this, [e]);\r
+               }\r
+\r
+               // Bind the function to the two event listeners\r
+               return this.mouseover(handleHover).mouseout(handleHover);\r
+       },\r
+       ready: function(f) {\r
+               // If the DOM is already ready\r
+               if ( jQuery.isReady )\r
+                       // Execute the function immediately\r
+                       f.apply( document, [jQuery] );\r
+\r
+               // Otherwise, remember the function for later\r
+               else {\r
+                       // Add the function to the wait list\r
+                       jQuery.readyList.push( function() { return f.apply(this, [jQuery]) } );\r
+               }\r
+\r
+               return this;\r
+       }\r
+});\r
+\r
+jQuery.extend({\r
+       /*\r
+        * All the code that makes DOM Ready work nicely.\r
+        */\r
+       isReady: false,\r
+       readyList: [],\r
+\r
+       // Handle when the DOM is ready\r
+       ready: function() {\r
+               // Make sure that the DOM is not already loaded\r
+               if ( !jQuery.isReady ) {\r
+                       // Remember that the DOM is ready\r
+                       jQuery.isReady = true;\r
+\r
+                       // If there are functions bound, to execute\r
+                       if ( jQuery.readyList ) {\r
+                               // Execute all of them\r
+                               jQuery.each( jQuery.readyList, function(){\r
+                                       this.apply( document );\r
+                               });\r
+\r
+                               // Reset the list of functions\r
+                               jQuery.readyList = null;\r
+                       }\r
+                       // Remove event lisenter to avoid memory leak\r
+                       if ( jQuery.browser.mozilla || jQuery.browser.opera )\r
+                               document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );\r
+               }\r
+       }\r
+});\r
+\r
+new function(){\r
+\r
+       jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +\r
+               "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +\r
+               "submit,keydown,keypress,keyup,error").split(","), function(i,o){\r
+\r
+               // Handle event binding\r
+               jQuery.fn[o] = function(f){\r
+                       return f ? this.bind(o, f) : this.trigger(o);\r
+               };\r
+\r
+       });\r
+\r
+       // If Mozilla is used\r
+       if ( jQuery.browser.mozilla || jQuery.browser.opera )\r
+               // Use the handy event callback\r
+               document.addEventListener( "DOMContentLoaded", jQuery.ready, false );\r
+\r
+       // If IE is used, use the excellent hack by Matthias Miller\r
+       // http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited\r
+       else if ( jQuery.browser.msie ) {\r
+\r
+               // Only works if you document.write() it\r
+               document.write("<scr" + "ipt id=__ie_init defer=true " +\r
+                       "src=//:><\/script>");\r
+\r
+               // Use the defer script hack\r
+               var script = document.getElementById("__ie_init");\r
+\r
+               // script does not exist if jQuery is loaded dynamically\r
+               if ( script )\r
+                       script.onreadystatechange = function() {\r
+                               if ( this.readyState != "complete" ) return;\r
+                               this.parentNode.removeChild( this );\r
+                               jQuery.ready();\r
+                       };\r
+\r
+               // Clear from memory\r
+               script = null;\r
+\r
+       // If Safari  is used\r
+       } else if ( jQuery.browser.safari )\r
+               // Continually check to see if the document.readyState is valid\r
+               jQuery.safariTimer = setInterval(function(){\r
+                       // loaded and complete are both valid states\r
+                       if ( document.readyState == "loaded" ||\r
+                               document.readyState == "complete" ) {\r
+\r
+                               // If either one are found, remove the timer\r
+                               clearInterval( jQuery.safariTimer );\r
+                               jQuery.safariTimer = null;\r
+\r
+                               // and execute any waiting functions\r
+                               jQuery.ready();\r
+                       }\r
+               }, 10);\r
+\r
+       // A fallback to window.onload, that will always work\r
+       jQuery.event.add( window, "load", jQuery.ready );\r
+\r
+};\r
+\r
+// Clean up after IE to avoid memory leaks\r
+if (jQuery.browser.msie)\r
+       jQuery(window).one("unload", function() {\r
+               var global = jQuery.event.global;\r
+               for ( var type in global ) {\r
+                       var els = global[type], i = els.length;\r
+                       if ( i && type != 'unload' )\r
+                               do\r
+                                       jQuery.event.remove(els[i-1], type);\r
+                               while (--i);\r
+               }\r
+       });\r
+jQuery.fn.extend({\r
+       loadIfModified: function( url, params, callback ) {\r
+               this.load( url, params, callback, 1 );\r
+       },\r
+       load: function( url, params, callback, ifModified ) {\r
+               if ( jQuery.isFunction( url ) )\r
+                       return this.bind("load", url);\r
+\r
+               callback = callback || function(){};\r
+\r
+               // Default to a GET request\r
+               var type = "GET";\r
+\r
+               // If the second parameter was provided\r
+               if ( params )\r
+                       // If it's a function\r
+                       if ( jQuery.isFunction( params ) ) {\r
+                               // We assume that it's the callback\r
+                               callback = params;\r
+                               params = null;\r
+\r
+                       // Otherwise, build a param string\r
+                       } else {\r
+                               params = jQuery.param( params );\r
+                               type = "POST";\r
+                       }\r
+\r
+               var self = this;\r
+\r
+               // Request the remote document\r
+               jQuery.ajax({\r
+                       url: url,\r
+                       type: type,\r
+                       data: params,\r
+                       ifModified: ifModified,\r
+                       complete: function(res, status){\r
+                               if ( status == "success" || !ifModified && status == "notmodified" )\r
+                                       // Inject the HTML into all the matched elements\r
+                                       self.attr("innerHTML", res.responseText)\r
+                                         // Execute all the scripts inside of the newly-injected HTML\r
+                                         .evalScripts()\r
+                                         // Execute callback\r
+                                         .each( callback, [res.responseText, status, res] );\r
+                               else\r
+                                       callback.apply( self, [res.responseText, status, res] );\r
+                       }\r
+               });\r
+               return this;\r
+       },\r
+       serialize: function() {\r
+               return jQuery.param( this );\r
+       },\r
+       evalScripts: function() {\r
+               return this.find("script").each(function(){\r
+                       if ( this.src )\r
+                               jQuery.getScript( this.src );\r
+                       else\r
+                               jQuery.globalEval( this.text || this.textContent || this.innerHTML || "" );\r
+               }).end();\r
+       }\r
+\r
+});\r
+\r
+// If IE is used, create a wrapper for the XMLHttpRequest object\r
+if ( !window.XMLHttpRequest )\r
+       XMLHttpRequest = function(){\r
+               return new ActiveXObject("Microsoft.XMLHTTP");\r
+       };\r
+\r
+// Attach a bunch of functions for handling common AJAX events\r
+\r
+jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){\r
+       jQuery.fn[o] = function(f){\r
+               return this.bind(o, f);\r
+       };\r
+});\r
+\r
+jQuery.extend({\r
+       get: function( url, data, callback, type, ifModified ) {\r
+               // shift arguments if data argument was ommited\r
+               if ( jQuery.isFunction( data ) ) {\r
+                       callback = data;\r
+                       data = null;\r
+               }\r
+\r
+               return jQuery.ajax({\r
+                       url: url,\r
+                       data: data,\r
+                       success: callback,\r
+                       dataType: type,\r
+                       ifModified: ifModified\r
+               });\r
+       },\r
+       getIfModified: function( url, data, callback, type ) {\r
+               return jQuery.get(url, data, callback, type, 1);\r
+       },\r
+       getScript: function( url, callback ) {\r
+               return jQuery.get(url, null, callback, "script");\r
+       },\r
+       getJSON: function( url, data, callback ) {\r
+               return jQuery.get(url, data, callback, "json");\r
+       },\r
+       post: function( url, data, callback, type ) {\r
+               if ( jQuery.isFunction( data ) ) {\r
+                       callback = data;\r
+                       data = {};\r
+               }\r
+\r
+               return jQuery.ajax({\r
+                       type: "POST",\r
+                       url: url,\r
+                       data: data,\r
+                       success: callback,\r
+                       dataType: type\r
+               });\r
+       },\r
+\r
+       // timeout (ms)\r
+       //timeout: 0,\r
+       ajaxTimeout: function( timeout ) {\r
+               jQuery.ajaxSettings.timeout = timeout;\r
+       },\r
+       ajaxSetup: function( settings ) {\r
+               jQuery.extend( jQuery.ajaxSettings, settings );\r
+       },\r
+\r
+       ajaxSettings: {\r
+               global: true,\r
+               type: "GET",\r
+               timeout: 0,\r
+               contentType: "application/x-www-form-urlencoded",\r
+               processData: true,\r
+               async: true,\r
+               data: null\r
+       },\r
+\r
+       // Last-Modified header cache for next request\r
+       lastModified: {},\r
+       ajax: function( s ) {\r
+               // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout\r
+               s = jQuery.extend({}, jQuery.ajaxSettings, s);\r
+\r
+               // if data available\r
+               if ( s.data ) {\r
+                       // convert data if not already a string\r
+                       if (s.processData && typeof s.data != "string")\r
+                       s.data = jQuery.param(s.data);\r
+                       // append data to url for get requests\r
+                       if( s.type.toLowerCase() == "get" ) {\r
+                               // "?" + data or "&" + data (in case there are already params)\r
+                               s.url += ((s.url.indexOf("?") > -1) ? "&" : "?") + s.data;\r
+                               // IE likes to send both get and post data, prevent this\r
+                               s.data = null;\r
+                       }\r
+               }\r
+\r
+               // Watch for a new set of requests\r
+               if ( s.global && ! jQuery.active++ )\r
+                       jQuery.event.trigger( "ajaxStart" );\r
+\r
+               var requestDone = false;\r
+\r
+               // Create the request object\r
+               var xml = new XMLHttpRequest();\r
+\r
+               // Open the socket\r
+               xml.open(s.type, s.url, s.async);\r
+\r
+               // Set the correct header, if data is being sent\r
+               if ( s.data )\r
+                       xml.setRequestHeader("Content-Type", s.contentType);\r
+\r
+               // Set the If-Modified-Since header, if ifModified mode.\r
+               if ( s.ifModified )\r
+                       xml.setRequestHeader("If-Modified-Since",\r
+                               jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );\r
+\r
+               // Set header so the called script knows that it's an XMLHttpRequest\r
+               xml.setRequestHeader("X-Requested-With", "XMLHttpRequest");\r
+\r
+               // Make sure the browser sends the right content length\r
+               if ( xml.overrideMimeType )\r
+                       xml.setRequestHeader("Connection", "close");\r
+\r
+               // Allow custom headers/mimetypes\r
+               if( s.beforeSend )\r
+                       s.beforeSend(xml);\r
+\r
+               if ( s.global )\r
+                   jQuery.event.trigger("ajaxSend", [xml, s]);\r
+\r
+               // Wait for a response to come back\r
+               var onreadystatechange = function(isTimeout){\r
+                       // The transfer is complete and the data is available, or the request timed out\r
+                       if ( xml && (xml.readyState == 4 || isTimeout == "timeout") ) {\r
+                               requestDone = true;\r
+\r
+                               // clear poll interval\r
+                               if (ival) {\r
+                                       clearInterval(ival);\r
+                                       ival = null;\r
+                               }\r
+\r
+                               var status;\r
+                               try {\r
+                                       status = jQuery.httpSuccess( xml ) && isTimeout != "timeout" ?\r
+                                               s.ifModified && jQuery.httpNotModified( xml, s.url ) ? "notmodified" : "success" : "error";\r
+                                       // Make sure that the request was successful or notmodified\r
+                                       if ( status != "error" ) {\r
+                                               // Cache Last-Modified header, if ifModified mode.\r
+                                               var modRes;\r
+                                               try {\r
+                                                       modRes = xml.getResponseHeader("Last-Modified");\r
+                                               } catch(e) {} // swallow exception thrown by FF if header is not available\r
+\r
+                                               if ( s.ifModified && modRes )\r
+                                                       jQuery.lastModified[s.url] = modRes;\r
+\r
+                                               // process the data (runs the xml through httpData regardless of callback)\r
+                                               var data = jQuery.httpData( xml, s.dataType );\r
+\r
+                                               // If a local callback was specified, fire it and pass it the data\r
+                                               if ( s.success )\r
+                                                       s.success( data, status );\r
+\r
+                                               // Fire the global callback\r
+                                               if( s.global )\r
+                                                       jQuery.event.trigger( "ajaxSuccess", [xml, s] );\r
+                                       } else\r
+                                               jQuery.handleError(s, xml, status);\r
+                               } catch(e) {\r
+                                       status = "error";\r
+                                       jQuery.handleError(s, xml, status, e);\r
+                               }\r
+\r
+                               // The request was completed\r
+                               if( s.global )\r
+                                       jQuery.event.trigger( "ajaxComplete", [xml, s] );\r
+\r
+                               // Handle the global AJAX counter\r
+                               if ( s.global && ! --jQuery.active )\r
+                                       jQuery.event.trigger( "ajaxStop" );\r
+\r
+                               // Process result\r
+                               if ( s.complete )\r
+                                       s.complete(xml, status);\r
+\r
+                               // Stop memory leaks\r
+                               if(s.async)\r
+                                       xml = null;\r
+                       }\r
+               };\r
+\r
+               // don't attach the handler to the request, just poll it instead\r
+               var ival = setInterval(onreadystatechange, 13);\r
+\r
+               // Timeout checker\r
+               if ( s.timeout > 0 )\r
+                       setTimeout(function(){\r
+                               // Check to see if the request is still happening\r
+                               if ( xml ) {\r
+                                       // Cancel the request\r
+                                       xml.abort();\r
+\r
+                                       if( !requestDone )\r
+                                               onreadystatechange( "timeout" );\r
+                               }\r
+                       }, s.timeout);\r
+\r
+               // Send the data\r
+               try {\r
+                       xml.send(s.data);\r
+               } catch(e) {\r
+                       jQuery.handleError(s, xml, null, e);\r
+               }\r
+\r
+               // firefox 1.5 doesn't fire statechange for sync requests\r
+               if ( !s.async )\r
+                       onreadystatechange();\r
+\r
+               // return XMLHttpRequest to allow aborting the request etc.\r
+               return xml;\r
+       },\r
+\r
+       handleError: function( s, xml, status, e ) {\r
+               // If a local callback was specified, fire it\r
+               if ( s.error ) s.error( xml, status, e );\r
+\r
+               // Fire the global callback\r
+               if ( s.global )\r
+                       jQuery.event.trigger( "ajaxError", [xml, s, e] );\r
+       },\r
+\r
+       // Counter for holding the number of active queries\r
+       active: 0,\r
+\r
+       // Determines if an XMLHttpRequest was successful or not\r
+       httpSuccess: function( r ) {\r
+               try {\r
+                       return !r.status && location.protocol == "file:" ||\r
+                               ( r.status >= 200 && r.status < 300 ) || r.status == 304 ||\r
+                               jQuery.browser.safari && r.status == undefined;\r
+               } catch(e){}\r
+               return false;\r
+       },\r
+\r
+       // Determines if an XMLHttpRequest returns NotModified\r
+       httpNotModified: function( xml, url ) {\r
+               try {\r
+                       var xmlRes = xml.getResponseHeader("Last-Modified");\r
+\r
+                       // Firefox always returns 200. check Last-Modified date\r
+                       return xml.status == 304 || xmlRes == jQuery.lastModified[url] ||\r
+                               jQuery.browser.safari && xml.status == undefined;\r
+               } catch(e){}\r
+               return false;\r
+       },\r
+\r
+       /* Get the data out of an XMLHttpRequest.\r
+        * Return parsed XML if content-type header is "xml" and type is "xml" or omitted,\r
+        * otherwise return plain text.\r
+        * (String) data - The type of data that you're expecting back,\r
+        * (e.g. "xml", "html", "script")\r
+        */\r
+       httpData: function( r, type ) {\r
+               var ct = r.getResponseHeader("content-type");\r
+               var data = !type && ct && ct.indexOf("xml") >= 0;\r
+               data = type == "xml" || data ? r.responseXML : r.responseText;\r
+\r
+               // If the type is "script", eval it in global context\r
+               if ( type == "script" )\r
+                       jQuery.globalEval( data );\r
+\r
+               // Get the JavaScript object, if JSON is used.\r
+               if ( type == "json" )\r
+                       eval( "data = " + data );\r
+\r
+               // evaluate scripts within html\r
+               if ( type == "html" )\r
+                       jQuery("<div>").html(data).evalScripts();\r
+\r
+               return data;\r
+       },\r
+\r
+       // Serialize an array of form elements or a set of\r
+       // key/values into a query string\r
+       param: function( a ) {\r
+               var s = [];\r
+\r
+               // If an array was passed in, assume that it is an array\r
+               // of form elements\r
+               if ( a.constructor == Array || a.jquery )\r
+                       // Serialize the form elements\r
+                       jQuery.each( a, function(){\r
+                               s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) );\r
+                       });\r
+\r
+               // Otherwise, assume that it's an object of key/value pairs\r
+               else\r
+                       // Serialize the key/values\r
+                       for ( var j in a )\r
+                               // If the value is an array then the key names need to be repeated\r
+                               if ( a[j] && a[j].constructor == Array )\r
+                                       jQuery.each( a[j], function(){\r
+                                               s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) );\r
+                                       });\r
+                               else\r
+                                       s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) );\r
+\r
+               // Return the resulting serialization\r
+               return s.join("&");\r
+       },\r
+\r
+       // evalulates a script in global context\r
+       // not reliable for safari\r
+       globalEval: function( data ) {\r
+               if ( window.execScript )\r
+                       window.execScript( data );\r
+               else if ( jQuery.browser.safari )\r
+                       // safari doesn't provide a synchronous global eval\r
+                       window.setTimeout( data, 0 );\r
+               else\r
+                       eval.call( window, data );\r
+       }\r
+\r
+});\r
+jQuery.fn.extend({\r
+\r
+       show: function(speed,callback){\r
+               var hidden = this.filter(":hidden");\r
+               speed ?\r
+                       hidden.animate({\r
+                               height: "show", width: "show", opacity: "show"\r
+                       }, speed, callback) :\r
+\r
+                       hidden.each(function(){\r
+                               this.style.display = this.oldblock ? this.oldblock : "";\r
+                               if ( jQuery.css(this,"display") == "none" )\r
+                                       this.style.display = "block";\r
+                       });\r
+               return this;\r
+       },\r
+\r
+       hide: function(speed,callback){\r
+               var visible = this.filter(":visible");\r
+               speed ?\r
+                       visible.animate({\r
+                               height: "hide", width: "hide", opacity: "hide"\r
+                       }, speed, callback) :\r
+\r
+                       visible.each(function(){\r
+                               this.oldblock = this.oldblock || jQuery.css(this,"display");\r
+                               if ( this.oldblock == "none" )\r
+                                       this.oldblock = "block";\r
+                               this.style.display = "none";\r
+                       });\r
+               return this;\r
+       },\r
+\r
+       // Save the old toggle function\r
+       _toggle: jQuery.fn.toggle,\r
+       toggle: function( fn, fn2 ){\r
+               var args = arguments;\r
+               return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?\r
+                       this._toggle( fn, fn2 ) :\r
+                       this.each(function(){\r
+                               jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]\r
+                                       .apply( jQuery(this), args );\r
+                       });\r
+       },\r
+       slideDown: function(speed,callback){\r
+               return this.animate({height: "show"}, speed, callback);\r
+       },\r
+       slideUp: function(speed,callback){\r
+               return this.animate({height: "hide"}, speed, callback);\r
+       },\r
+       slideToggle: function(speed, callback){\r
+               return this.each(function(){\r
+                       var state = jQuery(this).is(":hidden") ? "show" : "hide";\r
+                       jQuery(this).animate({height: state}, speed, callback);\r
+               });\r
+       },\r
+       fadeIn: function(speed, callback){\r
+               return this.animate({opacity: "show"}, speed, callback);\r
+       },\r
+       fadeOut: function(speed, callback){\r
+               return this.animate({opacity: "hide"}, speed, callback);\r
+       },\r
+       fadeTo: function(speed,to,callback){\r
+               return this.animate({opacity: to}, speed, callback);\r
+       },\r
+       animate: function( prop, speed, easing, callback ) {\r
+               return this.queue(function(){\r
+\r
+                       this.curAnim = jQuery.extend({}, prop);\r
+                       var opt = jQuery.speed(speed, easing, callback);\r
+\r
+                       for ( var p in prop ) {\r
+                               var e = new jQuery.fx( this, opt, p );\r
+                               if ( prop[p].constructor == Number )\r
+                                       e.custom( e.cur(), prop[p] );\r
+                               else\r
+                                       e[ prop[p] ]( prop );\r
+                       }\r
+\r
+               });\r
+       },\r
+       queue: function(type,fn){\r
+               if ( !fn ) {\r
+                       fn = type;\r
+                       type = "fx";\r
+               }\r
+\r
+               return this.each(function(){\r
+                       if ( !this.queue )\r
+                               this.queue = {};\r
+\r
+                       if ( !this.queue[type] )\r
+                               this.queue[type] = [];\r
+\r
+                       this.queue[type].push( fn );\r
+\r
+                       if ( this.queue[type].length == 1 )\r
+                               fn.apply(this);\r
+               });\r
+       }\r
+\r
+});\r
+\r
+jQuery.extend({\r
+\r
+       speed: function(speed, easing, fn) {\r
+               var opt = speed && speed.constructor == Object ? speed : {\r
+                       complete: fn || !fn && easing ||\r
+                               jQuery.isFunction( speed ) && speed,\r
+                       duration: speed,\r
+                       easing: fn && easing || easing && easing.constructor != Function && easing\r
+               };\r
+\r
+               opt.duration = (opt.duration && opt.duration.constructor == Number ?\r
+                       opt.duration :\r
+                       { slow: 600, fast: 200 }[opt.duration]) || 400;\r
+\r
+               // Queueing\r
+               opt.old = opt.complete;\r
+               opt.complete = function(){\r
+                       jQuery.dequeue(this, "fx");\r
+                       if ( jQuery.isFunction( opt.old ) )\r
+                               opt.old.apply( this );\r
+               };\r
+\r
+               return opt;\r
+       },\r
+\r
+       easing: {},\r
+\r
+       queue: {},\r
+\r
+       dequeue: function(elem,type){\r
+               type = type || "fx";\r
+\r
+               if ( elem.queue && elem.queue[type] ) {\r
+                       // Remove self\r
+                       elem.queue[type].shift();\r
+\r
+                       // Get next function\r
+                       var f = elem.queue[type][0];\r
+\r
+                       if ( f ) f.apply( elem );\r
+               }\r
+       },\r
+\r
+       /*\r
+        * I originally wrote fx() as a clone of moo.fx and in the process\r
+        * of making it small in size the code became illegible to sane\r
+        * people. You've been warned.\r
+        */\r
+\r
+       fx: function( elem, options, prop ){\r
+\r
+               var z = this;\r
+\r
+               // The styles\r
+               var y = elem.style;\r
+\r
+               // Store display property\r
+               var oldDisplay = jQuery.css(elem, "display");\r
+\r
+               // Make sure that nothing sneaks out\r
+               y.overflow = "hidden";\r
+\r
+               // Simple function for setting a style value\r
+               z.a = function(){\r
+                       if ( options.step )\r
+                               options.step.apply( elem, [ z.now ] );\r
+\r
+                       if ( prop == "opacity" )\r
+                               jQuery.attr(y, "opacity", z.now); // Let attr handle opacity\r
+                       else if ( parseInt(z.now) ) // My hate for IE will never die\r
+                               y[prop] = parseInt(z.now) + "px";\r
+\r
+                       y.display = "block"; // Set display property to block for animation\r
+               };\r
+\r
+               // Figure out the maximum number to run to\r
+               z.max = function(){\r
+                       return parseFloat( jQuery.css(elem,prop) );\r
+               };\r
+\r
+               // Get the current size\r
+               z.cur = function(){\r
+                       var r = parseFloat( jQuery.curCSS(elem, prop) );\r
+                       return r && r > -10000 ? r : z.max();\r
+               };\r
+\r
+               // Start an animation from one number to another\r
+               z.custom = function(from,to){\r
+                       z.startTime = (new Date()).getTime();\r
+                       z.now = from;\r
+                       z.a();\r
+\r
+                       z.timer = setInterval(function(){\r
+                               z.step(from, to);\r
+                       }, 13);\r
+               };\r
+\r
+               // Simple 'show' function\r
+               z.show = function(){\r
+                       if ( !elem.orig ) elem.orig = {};\r
+\r
+                       // Remember where we started, so that we can go back to it later\r
+                       elem.orig[prop] = this.cur();\r
+\r
+                       options.show = true;\r
+\r
+                       // Begin the animation\r
+                       z.custom(0, elem.orig[prop]);\r
+\r
+                       // Stupid IE, look what you made me do\r
+                       if ( prop != "opacity" )\r
+                               y[prop] = "1px";\r
+               };\r
+\r
+               // Simple 'hide' function\r
+               z.hide = function(){\r
+                       if ( !elem.orig ) elem.orig = {};\r
+\r
+                       // Remember where we started, so that we can go back to it later\r
+                       elem.orig[prop] = this.cur();\r
+\r
+                       options.hide = true;\r
+\r
+                       // Begin the animation\r
+                       z.custom(elem.orig[prop], 0);\r
+               };\r
+\r
+               //Simple 'toggle' function\r
+               z.toggle = function() {\r
+                       if ( !elem.orig ) elem.orig = {};\r
+\r
+                       // Remember where we started, so that we can go back to it later\r
+                       elem.orig[prop] = this.cur();\r
+\r
+                       if(oldDisplay == "none")  {\r
+                               options.show = true;\r
+\r
+                               // Stupid IE, look what you made me do\r
+                               if ( prop != "opacity" )\r
+                                       y[prop] = "1px";\r
+\r
+                               // Begin the animation\r
+                               z.custom(0, elem.orig[prop]);\r
+                       } else {\r
+                               options.hide = true;\r
+\r
+                               // Begin the animation\r
+                               z.custom(elem.orig[prop], 0);\r
+                       }\r
+               };\r
+\r
+               // Each step of an animation\r
+               z.step = function(firstNum, lastNum){\r
+                       var t = (new Date()).getTime();\r
+\r
+                       if (t > options.duration + z.startTime) {\r
+                               // Stop the timer\r
+                               clearInterval(z.timer);\r
+                               z.timer = null;\r
+\r
+                               z.now = lastNum;\r
+                               z.a();\r
+\r
+                               if (elem.curAnim) elem.curAnim[ prop ] = true;\r
+\r
+                               var done = true;\r
+                               for ( var i in elem.curAnim )\r
+                                       if ( elem.curAnim[i] !== true )\r
+                                               done = false;\r
+\r
+                               if ( done ) {\r
+                                       // Reset the overflow\r
+                                       y.overflow = "";\r
+\r
+                                       // Reset the display\r
+                                       y.display = oldDisplay;\r
+                                       if (jQuery.css(elem, "display") == "none")\r
+                                               y.display = "block";\r
+\r
+                                       // Hide the element if the "hide" operation was done\r
+                                       if ( options.hide )\r
+                                               y.display = "none";\r
+\r
+                                       // Reset the properties, if the item has been hidden or shown\r
+                                       if ( options.hide || options.show )\r
+                                               for ( var p in elem.curAnim )\r
+                                                       if (p == "opacity")\r
+                                                               jQuery.attr(y, p, elem.orig[p]);\r
+                                                       else\r
+                                                               y[p] = "";\r
+                               }\r
+\r
+                               // If a callback was provided, execute it\r
+                               if ( done && jQuery.isFunction( options.complete ) )\r
+                                       // Execute the complete function\r
+                                       options.complete.apply( elem );\r
+                       } else {\r
+                               var n = t - this.startTime;\r
+                               // Figure out where in the animation we are and set the number\r
+                               var p = n / options.duration;\r
+\r
+                               // If the easing function exists, then use it\r
+                               z.now = options.easing && jQuery.easing[options.easing] ?\r
+                                       jQuery.easing[options.easing](p, n,  firstNum, (lastNum-firstNum), options.duration) :\r
+                                       // else use default linear easing\r
+                                       ((-Math.cos(p*Math.PI)/2) + 0.5) * (lastNum-firstNum) + firstNum;\r
+\r
+                               // Perform the next step of the animation\r
+                               z.a();\r
+                       }\r
+               };\r
+\r
+       }\r
+});\r
+}\r
diff --git a/lock.txt b/lock.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/lock2.txt b/lock2.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/main.css b/main.css
new file mode 100644 (file)
index 0000000..473fdff
--- /dev/null
+++ b/main.css
@@ -0,0 +1,35 @@
+/* \83`\83\83\83b\83g\89ï\98b\97\93\82Ì\90Ý\92è */\r
+@charset "Shift_JIS";\r
+\r
+/* \83\81\83C\83\93 */\r
+html {\r
+       font-weight: normal;\r
+}\r
+\r
+body {\r
+       background: #FFFFFF;\r
+       padding: 0px;\r
+       }\r
+\r
+/* \8cÂ\95Ê */\r
+.com_row {\r
+       font-size: 12px;\r
+       line-height: 2em;\r
+}\r
+\r
+.status {\r
+       color:#6D749C;\r
+}\r
+\r
+.member {\r
+       font-weight:bold;\r
+       text-decoration: none;\r
+}\r
+\r
+a.member:link, a.member:visited {\r
+       color:#1b0172;\r
+}\r
+\r
+a.member:hover {\r
+       color:#ffcd06;\r
+}
\ No newline at end of file
diff --git a/main.php b/main.php
new file mode 100644 (file)
index 0000000..d0a2889
--- /dev/null
+++ b/main.php
@@ -0,0 +1,261 @@
+<?php
+/*
+ * Ajax Chat for TRPG ver.1.0
+ * (c)2007 Cake All righ1ts reserved.
+ * Mail : cake_67@users.sourceforge.jp
+ * Home : http://trpgtools-onweb.sourceforge.jp/
+ *
+ * [注意事項他]
+ * 本チャットスクリプトの使用および配布は、BSDライセンスに基づきます。
+ * BSDライセンスの詳細につきましては、添付のライセンス.txtを参照してください。
+ *
+ * BSDライセンス概要&使用上の注意
+ * 1. このスクリプトはフリーソフトです。以下の条件を満たす限りにおいて、使用・改造・再配布(オリジナルおよび改造版の両方とも)は自由です。
+ * 再配布する場合、上記著作権表示、本条件書きおよび第2項・第3項の責任限定規定を必ず含めてください。
+ * 2. 同梱のアイコンはPetite Prier様(http://snow.if.tv/)の素材です。
+      本スクリプトの使用および再配布時にアイコンをそのまま用いる場合は、配布元の規定も遵守してください。
+ * 3. 本スクリプトは無保証です。自己責任で使用してください。このスクリプトを使用したいかなる損害に対しても、作者は一切の責任を負いません。
+ * 4. 設置および使用方法に関する質問は、配布サイトの掲示板にお願いします。ただし、必ず回答できるとは限りません。
+ * メールによる質問は、ご遠慮ください。
+ */
+
+// 設定ファイルの読み込み
+require_once 'trpgchat-ini.php';
+
+// HTML出力
+print html_header('main', $title.' ログ表示画面', true, true);
+
+ ?>
+
+<script type="text/javascript">
+<!--
+
+//変数の設定
+var getdata_on = <?php print $getdata_on;?>*1000;
+var getdata_off = <?php print $getdata_off;?>*1000;
+var logfile= '<?php print $recent_log;?>';
+var now_member = '<?php print $now_member;?>';
+var color_system = '#<?php print $color_system;?>';
+var status_color = '#<?php print $status_color; ?>';
+
+// 起動時の処理
+$(function()
+{
+    //ログの取得
+    getLog();
+    // タイマー
+    Timer = setInterval('getLog()', getdata_off);
+});
+
+// ログ取得
+function getLog(){
+    $.ajax({
+        type: "GET",
+        ifModified: true,
+        url: logfile,
+        success: function(data){
+    // 最新行番号の取得
+    if (!isNaN(document.getElementById('id'))) {
+        last_id = 0;
+    } else {
+        last_id = document.getElementById('id').firstChild.nodeValue;
+    }
+
+    // ログの整形
+        var recent = data.split('\n');
+
+        var text = new Array();
+        for(var i=0;i<recent.length; i++){
+        // 各行を<>で分割して配列に
+            var unit = recent[i].split('<>');
+
+        // データがなければ終了
+            // last_idで終点判断
+            if(unit[0] && last_id < unit[0]){
+                text[i] = setData(unit);
+            } else {
+                break;
+            }
+        }
+
+        var text_rev = text.reverse();
+
+        for(var i=0;i<text_rev.length; i++){
+        //出力
+            $("#online").after(text_rev[i]);
+        }
+    }
+    });
+    // 在室表示
+    showMember();
+}
+
+// 在室表示
+function showMember() {
+    $.ajax({
+        type: "GET",
+        ifModified: true,
+        url: now_member,
+        success: function(data2){
+        // ログの整形
+            var member = data2.split('\n');
+            var text2 = "";
+            var unit2 = new Array();
+            for(var i=0;i<member.length; i++){
+                var unit2 = member[i].split('<>');
+        // データがなければ終了
+                if(!unit2[0]){
+                    break;
+                }
+                var text2 = text2+'<span id="'+unit2[0]+'" class="member" onclick="inputWhisper(\''+unit2[0]+'\',\''+unit2[1]+'\')">'+unit2[0]+'</span>'+'<>';
+                // my_hashに自分のハッシュ登録
+                if (!$(window.parent.document.getElementById("my_hash")).attr("value") && $(window.parent.document.getElementById("pwd_on")).attr("value") && $(window.parent.document.getElementById("name_on")).attr("value")==unit2[0]) {
+                    window.parent.document.getElementById("my_hash").value = unit2[1];
+                }
+            }
+    // 出力
+            if (text2) {
+                $("#indi").html(text2);
+            }
+        }
+    });
+}
+
+// ログイン・ログオフ
+function login() {
+    clearInterval(Timer);
+    Timer = setInterval('getLog()', getdata_on);
+    $("#help").hide();
+    $("#online").show();
+    clearLog();
+}
+function logout() {
+    clearInterval(Timer);
+    Timer = setInterval('getLog()', getdata_off);
+    window.parent.document.getElementById("whisper_mark").src="<?php print $whisper_on; ?>"
+    window.location.reload();
+}
+
+// リフレッシュ
+function clearLog(){
+    $(".com_row").remove();
+    $.ajax({
+        type: "GET",
+        ifModified: false,
+        url: logfile,
+        success: function(data){
+        var recent = data.split('\n');
+        var text = new Array();
+        for(var i=0;i<recent.length; i++){
+            var unit = recent[i].split('<>');
+            if (unit[0]) {
+                text[i] = setData(unit);
+            }
+        }
+        var text_rev = text.reverse();
+        for(var i=0;i<text_rev.length; i++){
+        //出力
+            if(text_rev[i]){
+                $("#online").after(text_rev[i]);
+            }
+        }
+    }
+    });
+}
+
+// ささやき指定
+function inputWhisper(name, whisperTo) {
+    var flag = whisperTo ? true : false;
+    if (flag==false){
+        alert(name+"さんは入室パスワード未入力のため、「ささやき」はできません。");
+    } else if (!window.parent.document.getElementById("pwd_on").value){
+        alert("パスワードを入力しないと「ささやき」はできません。");
+    } else if (name=='全員'){
+        alert("「全員」という名前の方に「ささやき」はできません(笑)");
+    } else {
+        window.parent.document.getElementById("whisper_to").value = name;
+        window.parent.document.getElementById("whisper_to_hash").value = whisperTo;
+        window.parent.document.getElementById("whisper_mark").src="<?php print $whisper_on; ?>"
+    }
+}
+
+// ログ行整形
+function setData(unit) {
+    if (!unit) {
+        return false;
+    }
+    //行番号:最新行
+    var last_id_tag = '<span id="id" style="display:none;">'+unit[0]+'</span>';
+    //データの整形
+    var name = decodeURIComponent(unit[1]);
+    var pc = decodeURIComponent(unit[2]);
+    var color = decodeURIComponent(unit[3]);
+    var com = decodeURIComponent(unit[4]);
+    var d = new Date();
+    d.setTime(unit[5]*1000);
+    var year = d.getYear();
+    if (year < 2000) { year += 1900;}
+    var month = d.getMonth()+1;
+    if (month < 10) { month = "0" + month;}
+    var day = d.getDate();
+    if (day < 10) { day = "0" + day;}
+    var hour = d.getHours();
+    if (hour < 10) { hour = "0" + hour;}
+    var min = d.getMinutes();
+    if (min < 10) { min = "0" + min;}
+    var sec = d.getSeconds();
+    if (sec < 10) { sec = "0" + sec;}
+    var datetime = year+'/'+month+'/'+day+' '+hour+':'+min+':'+sec;
+    var whisper = 'n';
+    if(unit[9] || unit[10]) {
+        var whisper = 'y';
+        if ($(window.parent.document.getElementById("my_hash")).attr("value") == unit[8]) whisper = 'to';
+        if ($(window.parent.document.getElementById("my_hash")).attr("value") == unit[10]) var whisper = 'from'
+    }
+    if(unit[11] == '1' && unit[12]) {
+        var status = decodeURIComponent(unit[12]);
+    }
+
+    // 行の整形
+    if (unit[0]!='0' && whisper!='y') {
+        row =
+        '<div class="com_row" id="com_row_'+unit[0]+'">'+last_id_tag+'<span style="font-weight:bold; color:'+color+';" id="'+unit[0]+'" title="'+name+'">【'+pc+'】</span>:'+
+        '<span class="body" title="'+datetime+'">';
+        if (whisper=='to' || whisper=='from') {
+            row = row+'<span style="color:'+color_system+';">(';
+            if (whisper=='to') row = row+unit[9]+'さんへ';
+            if (whisper=='from') row = row+unit[2]+'さんから';
+            row = row+'のささやき) </span>';
+
+        }
+        row = row+com+'</span>';
+        if (status) {
+            row = row+' <span style="color:'+status_color+';">('+status+')</span>';
+        }
+        row = row+'</div>';
+    } else {
+        row = last_id_tag;
+    }
+    return row;
+}
+//-->
+</script>
+</head>
+<body>
+<div id="help" class="help" style="display:inline;">
+<?php print nl2br($help);?>
+<hr>
+</div>
+<div id="online" class="online" style="display:none;">参加者: <span id="indi"></span></div>
+
+<div align="right" id="pastlog" class="pastlog">
+<a href="./pastlog_index.php" target="pastlog">もっと前のログを見る</a></div>
+
+<noscript>
+<p><img src="image/blog_jscript.gif" alt="Javascript" width="80" height="15">本チャットは、JavaScript が有効な環境でのみ使用可能です。</p>
+</noscript>
+
+<?php
+// フッター
+print html_footer('');
+ ?>
\ No newline at end of file
diff --git a/master_past/index.html b/master_past/index.html
new file mode 100644 (file)
index 0000000..e7692e6
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\r
+<title>TRPGのためのAjaxチャット</title>\r
+</head>\r
+<body>\r
+\r
+TRPGのためのAjaxChat配布サイトは<a href="http://trpgtools-onweb.sourceforge.jp/">こちら。</a>\r
+\r
+</body>\r
+</html>\r
diff --git a/member.log b/member.log
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/member_check.php b/member_check.php
new file mode 100644 (file)
index 0000000..cf000cc
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+/*
+ * Ajax Chat for TRPG ver.1.0
+ * (c)2007 Cake All righ1ts reserved.
+ * Mail : cake_67@users.sourceforge.jp
+ * Home : http://trpgtools-onweb.sourceforge.jp/
+ *
+ * [注意事項他]
+ * 本チャットスクリプトの使用および配布は、BSDライセンスに基づきます。
+ * BSDライセンスの詳細につきましては、添付のライセンス.txtを参照してください。
+ *
+ * BSDライセンス概要&使用上の注意
+ * 1. このスクリプトはフリーソフトです。以下の条件を満たす限りにおいて、使用・改造・再配布(オリジナルおよび改造版の両方とも)は自由です。
+ * 再配布する場合、上記著作権表示、本条件書きおよび第2項・第3項の責任限定規定を必ず含めてください。
+ * 2. 同梱のアイコンはPetite Prier様(http://snow.if.tv/)の素材です。
+      本スクリプトの使用および再配布時にアイコンをそのまま用いる場合は、配布元の規定も遵守してください。
+ * 3. 本スクリプトは無保証です。自己責任で使用してください。このスクリプトを使用したいかなる損害に対しても、作者は一切の責任を負いません。
+ * 4. 設置および使用方法に関する質問は、配布サイトの掲示板にお願いします。ただし、必ず回答できるとは限りません。
+ * メールによる質問は、ご遠慮ください。
+ */
+
+// 設定ファイルの読み込み
+require_once 'trpgchat-ini.php';
+
+/* メンバーチェッカー */
+function member_checker($name='', $hash='', $mode='', $now_member, $getdata_off) {
+
+//echo "1";
+//echo $name."<>".$hash."<>".$mode."<>".$getdata_off."<P>";
+
+    // ファイルロック
+    $lfp2 = fopen($lockfile2,"w");\r
+    stream_set_write_buffer($lfp2, 0);
+    flock($lfp2,LOCK_EX);
+
+    // 初期化
+    $member_data = array();
+    $member = array();
+    $write = array();
+
+    // 既存ファイル内容の格納
+    $member_data[] = file($now_member);
+//print_r($member_data);
+//echo "<P>";
+    $flag = 0;
+    if ($member_data[0]) {
+        foreach ($member_data[0] as $k => $v) {
+            $member[$k] = explode("<>", $v);
+//echo "<P>".$k;
+//print_r($member[$k]);
+            // ログアウト:削除
+            if ($mode == "out" && $member[$k][0] == $name && $member[$k][1] == $hash) {
+                $flag = 1;
+            // 名前とパスが一致すれば在室時間更新
+            } elseif ($member[$k][0] == $name && $member[$k][1] == $hash) {
+                $member[$k][2] = time();
+                // コメント時、発言時間更新
+                if ($mode=="com") {
+                    $member[$k][3] = time();
+                }
+
+                $write[] = implode("<>",$member[$k]);
+//echo "<P>icchi:";
+//print_r($write);
+                $flag = 1;
+                // ROM更新時間($getdata_off)x10(秒)以内の名前のみ保存:それ以上経過した名前は削除
+            } elseif ((time() - $member[$k][2]) < ($getdata_off * 10)) {
+//                $write[] = implode("<>",$member[$k]);
+                $write[] = $v;
+//echo "<P>pass:";
+//print_r($write);
+            }
+        }
+    }
+    // ログに名前追加
+    if ($mode != "out" && $flag == 0 && $name) {
+        $write[] = $name."<>".$hash."<>".time()."<>".time()."<>\n";
+    }
+
+//echo "<P>";
+//print_r($write);
+//exit;
+    // ログファイル更新
+    $fpm = @fopen($now_member, "w+") or die("ログファイルを開けません2");
+    //$bom = "\xef\xbb\xbf";
+    //fwrite($fpm, $bom);
+
+        foreach($write as $k => $v) {
+            fwrite($fpm, $v);
+        }
+    fclose($fpm);
+
+    // ロック解除
+    fflush($lfp2);
+    fclose($lfp2);
+}
+?>
\ No newline at end of file
diff --git a/past/index.html b/past/index.html
new file mode 100644 (file)
index 0000000..e7692e6
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\r
+<title>TRPGのためのAjaxチャット</title>\r
+</head>\r
+<body>\r
+\r
+TRPGのためのAjaxChat配布サイトは<a href="http://trpgtools-onweb.sourceforge.jp/">こちら。</a>\r
+\r
+</body>\r
+</html>\r
diff --git a/pastlog-ini.php b/pastlog-ini.php
new file mode 100644 (file)
index 0000000..cddbad7
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/*
+ * Ajax Chat for TRPG ver.1.0
+ * (c)2007 Cake All righ1ts reserved.
+ * Mail : cake_67@users.sourceforge.jp
+ * Home : http://trpgtools-onweb.sourceforge.jp/
+ *
+ * [注意事項他]
+ * 本チャットスクリプトの使用および配布は、BSDライセンスに基づきます。
+ * BSDライセンスの詳細につきましては、添付のライセンス.txtを参照してください。
+ *
+ * BSDライセンス概要&使用上の注意
+ * 1. このスクリプトはフリーソフトです。以下の条件を満たす限りにおいて、使用・改造・再配布(オリジナルおよび改造版の両方とも)は自由です。
+ * 再配布する場合、上記著作権表示、本条件書きおよび第2項・第3項の責任限定規定を必ず含めてください。
+ * 2. 同梱のアイコンはPetite Prier様(http://snow.if.tv/)の素材です。
+      本スクリプトの使用および再配布時にアイコンをそのまま用いる場合は、配布元の規定も遵守してください。
+ * 3. 本スクリプトは無保証です。自己責任で使用してください。このスクリプトを使用したいかなる損害に対しても、作者は一切の責任を負いません。
+ * 4. 設置および使用方法に関する質問は、配布サイトの掲示板にお願いします。ただし、必ず回答できるとは限りません。
+ * メールによる質問は、ご遠慮ください。
+ */
+function read_log ($logfile, $hash, $masterpass, $d, $color_system) {
+
+    // ログの読み込み
+    $log = array();
+    $log = file($logfile);
+    if (is_array($log)) {
+
+        // データの整形
+        foreach($log as $k => $v) {
+            if ($v[0] != 0) {
+                $unit = explode("<>", $v);
+                $num = $unit[0];
+                $name = $unit[1];
+                $pc = $unit[2];
+                $color = $unit[3];
+                $com = $unit[4];
+                if ($d) $datetime = date("Y/m/d H:i:s", $unit[5]);
+                if ($masterpass && $hash == $masterpass) $host = '<!-- '.$unit[6].' -->';
+                $whisper_from_pass = $unit[8];
+                $whisper_to_name = $unit[9];
+                $whisper_to_pass = $unit[10];
+
+                $w = 'n';
+                if($unit[9] || $unit[10]) {
+                    $w = 'y';
+                    if ($hash == $unit[8]) {
+                        $w = 'to';
+                    } elseif ($hash == $unit[10]) {
+                        $w = 'from';
+                    } elseif ($masterpass) {
+                        $w = 'from';
+                    }
+                }
+
+                // 行の整形
+                if ($num && $w != 'y') {
+                    $row[$k] = '<span style="font-weight:bold; color:#'.$color.';" title="'.$name.'">【'.$pc.'】</span>:';
+                    if ($w == 'to' || $w == 'from') {
+                        $row[$k] .= '<span style="color:#'.$color_system.'">(';
+                        if ($w == 'to') $row[$k] .= $unit[9].'さんへ';
+                        if ($w == 'from') $row[$k] .= $unit[2].'さんから';
+                        $row[$k] .= 'のささやき) </span>';
+                    }
+                    if ($d) $row[$k] .= '<span title="'.$datetime.'">';
+                    $row[$k] .= $com;
+                    if ($d) $row[$k] .= '</span>';
+                    $row[$k] .= $host;
+                }
+            }
+        }
+    }
+    return $row;
+}
+
+ ?>
\ No newline at end of file
diff --git a/pastlog.php b/pastlog.php
new file mode 100644 (file)
index 0000000..44389c1
--- /dev/null
@@ -0,0 +1,275 @@
+<?php
+/*
+ * Ajax Chat for TRPG ver.1.0
+ * (c)2007 Cake All righ1ts reserved.
+ * Mail : cake_67@users.sourceforge.jp
+ * Home : http://trpgtools-onweb.sourceforge.jp/
+ *
+ * [注意事項他]
+ * 本チャットスクリプトの使用および配布は、BSDライセンスに基づきます。
+ * BSDライセンスの詳細につきましては、添付のライセンス.txtを参照してください。
+ *
+ * BSDライセンス概要&使用上の注意
+ * 1. このスクリプトはフリーソフトです。以下の条件を満たす限りにおいて、使用・改造・再配布(オリジナルおよび改造版の両方とも)は自由です。
+ * 再配布する場合、上記著作権表示、本条件書きおよび第2項・第3項の責任限定規定を必ず含めてください。
+ * 2. 同梱のアイコンはPetite Prier様(http://snow.if.tv/)の素材です。
+      本スクリプトの使用および再配布時にアイコンをそのまま用いる場合は、配布元の規定も遵守してください。
+ * 3. 本スクリプトは無保証です。自己責任で使用してください。このスクリプトを使用したいかなる損害に対しても、作者は一切の責任を負いません。
+ * 4. 設置および使用方法に関する質問は、配布サイトの掲示板にお願いします。ただし、必ず回答できるとは限りません。
+ * メールによる質問は、ご遠慮ください。
+ */
+
+// 設定ファイルの読み込み
+require_once './trpgchat-ini.php';
+require_once './pastlog-ini.php';
+
+// パスワードの照合
+if ($masterpass && $_REQUEST['admin_pwd'] != $masterpass) error('パスワードが違います。');
+
+/* 送信内容別 */
+// 過去ログ削除確認
+if ($_REQUEST['mode'] == 'delete_log_confirm') {
+    if ($_REQUEST['type'] == 'public') {
+        $dir = $past_dir;
+    } elseif ($_REQUEST['type'] == 'admin') {
+        $dir = $master_past_dir;
+    } else {
+        error('データが正しく送信されていません。');
+    }
+    $type = $_REQUEST['type'];
+
+    if (!$_REQUEST['filename'][0]) {
+        error('ファイルを指定してください。');
+        exit;
+    }
+
+    print html_header('main', $title.' 過去ログ削除確認', false, true);
+
+    print '<h2>削除確認</h2>'."\n";
+    print '<p><font color="#FF0000">以下の過去ログを削除します。よろしいですか?</font></p>'."\n";
+    print '<form action="'.$pastlog_maker.'" method="'.$method.'">'."\n";
+    print '<input type="hidden" name="mode" value="delete_log">'."\n";
+    print '<input type="hidden" name="admin_pwd" value="'.$masterpass.'">'."\n";
+    print '<input type="hidden" name="type" value="'.$type.'">'."\n";
+    print '<ul>'."\n";
+    foreach ($_REQUEST['filename'] as $k => $v) {
+        print '<li><input type="hidden" name="filename[]" value="'.$v.'"> <a href="'.$dir.$v.'" target="admin_past">'.$v.'</a></li>'."\n";
+    }
+    print '</ul>'."\n";
+    print '<p><input type="submit" value="削除する"></p>'."\n";
+    print '</form>'."\n";
+    print html_footer('');
+    exit;
+
+// 過去ログ削除
+} elseif ($_REQUEST['mode'] == 'delete_log') {
+    if ($_REQUEST['type'] == 'public') {
+        $dir = $past_dir;
+    } elseif ($_REQUEST['type'] == 'admin') {
+        $dir = $master_past_dir;
+    } else {
+        error('データが正しく送信されていません。');
+    }
+
+    if (!$_REQUEST['filename'][0]) {
+        error('ファイルを指定してください。');
+        exit;
+    }
+
+    foreach($_REQUEST['filename'] as $v) {
+        if (file_exists($dir.$v)) unlink($dir.$v);
+    }
+    header("Location: $pastlog_maker?admin_pwd=$masterpass&mode=del_end");
+    exit;
+
+// 過去ログ作成
+} elseif ($_REQUEST['mode'] == 'write_log') {
+    write_log($past_dir, $master_past_dir, $past_log, $masterpass, $color_system, $copyright, $_REQUEST['datetime'], $_REQUEST['whisper'], $_REQUEST['filename']);
+    if ($_REQUEST['delete']) {
+        $fp = fopen($recent_log, "w");
+        fclose($fp);
+        $fp = fopen($past_log, "w");
+        fclose($fp);
+    }
+    header("Location: $pastlog_maker?admin_pwd=$masterpass&mode=write_end");
+    exit;
+
+// 過去ログ作成完了
+} elseif ($_REQUEST['mode'] == 'write_end') {
+    print html_header('main', $title.' 過去ログ作成完了', false, true);
+
+    print '<p>過去ログを作成しました。</p>'."\n";
+    print '<form action="'.$pastlog_maker.'" method="'.$method.'">'."\n";
+    print '<input type="hidden" name="mode" value="">'."\n";
+    print '<input type="hidden" name="admin_pwd" value="'.$masterpass.'">'."\n";
+    print '<p><input type="submit" value="戻る"></p>'."\n";
+    print '</form>'."\n";
+    print html_footer('');
+    exit;
+
+// 削除完了
+} elseif ($_REQUEST['mode'] == 'del_end') {
+    print html_header('main', $title.' 過去ログ削除完了', false, true);
+
+    print '<p>過去ログを削除しました。</p>'."\n";
+    print '<form action="'.$pastlog_maker.'" method="'.$method.'">'."\n";
+    print '<input type="hidden" name="mode" value="">'."\n";
+    print '<input type="hidden" name="admin_pwd" value="'.$masterpass.'">'."\n";
+    print '<p><input type="submit" value="戻る"></p>'."\n";
+    print '</form>'."\n";
+    print html_footer('');
+    exit;
+}
+
+// 画面表示:HTML出力
+print html_header('main', $title.' 過去ログ管理画面', false, true);
+
+?>
+</head>
+<body>
+<h2 align="center"><?php print $title; ?> 過去ログ管理画面</h2>
+
+<?php
+if ($_REQUEST['msg']) print '<p style="color:red">'.$_REQUEST['msg'].'</p>';
+?>
+
+<table cellspacing="0" align="center" border="1" bordercolor="#000000">
+<tr><td colspan="2">
+<form action="<?php print $pastlog_maker; ?>" method="<?php print $method; ?>" name="write_log">
+<input name="mode" type="hidden" value="write_log">
+<input name="admin_pwd" type="hidden" value="<?php print $_REQUEST['admin_pwd']; ?>">
+<table align="center" border="0">
+<tr>
+<td><input type="checkbox" name="datetime" value="1">
+発言時間表示</td>
+<td><input type="checkbox" name="whisper" value="1">ささやき全表示</td>
+<td><input checked type="checkbox" name="delete" value="1">ログ削除</td>
+</tr>
+<tr><td colspan="3" align="center">ログファイル名:<input name="filename" type="text" value="<?php print date('Ymd'); ?>" size="10" maxlength="30" style="ime-mode:disabled;">.html <input type="submit" value="過去ログ作成"></td></tr>
+</table></form>
+<span align="left">「ささやき全表示」:指定すると公開ログにも全ての「ささやき」が表示されます。<br>
+「ログ削除」:過去ログ作成と同時に、現在のログを全て削除します。<br></span>
+</td></tr>
+
+<tr>
+<td valign="top" width="50%">
+<h4>公開過去ログ</h4>
+
+<?php
+if ($log_list = log_list($past_dir)) {
+    print '<form action="./'.$pastlog_maker.'" method="'.$method.'">'."\n";
+    print '<input type="hidden" name="mode" value="delete_log_confirm">'."\n";
+    print '<input type="hidden" name="admin_pwd" value="'.$masterpass.'">'."\n";
+    print '<input type="hidden" name="type" value="public">'."\n";
+    print $log_list;
+    print '<br><input type="submit" value="削除確認">'."\n";
+    print '</form>'."\n";
+} else {
+    print '公開過去ログはありません。';
+}
+?>
+</td>
+<td valign="top" width="50%">
+<h4>管理用過去ログ(非公開)</h4>
+
+<?php
+if ($log_list = log_list($master_past_dir)) {
+    print '<form action="./'.$pastlog_maker.'" method="'.$method.'">'."\n";
+    print '<input type="hidden" name="mode" value="delete_log_confirm">'."\n";
+    print '<input type="hidden" name="admin_pwd" value="'.$masterpass.'">'."\n";
+    print '<input type="hidden" name="type" value="admin">'."\n";
+    print $log_list;
+    print '<br><input type="submit" value="削除確認">'."\n";
+    print '</form>'."\n";
+} else {
+    print '管理用過去ログはありません。';
+}
+?>
+
+<h5>管理用過去ログには、全ての発言時間・ささやき・参加者のホスト情報が記録されます</h5>
+
+</td>
+</tr>
+</table>
+
+<?php
+// フッター
+print html_footer($copyright);
+
+
+/* 関数 */
+// 過去ログ作成
+function  write_log($past_dir, $master_past_dir, $past_log, $masterpass, $color_system, $copyright, $datetime, $whisper, $filename) {
+    $log_master = read_log($past_log, $masterpass, $masterpass, true, $color_system);
+    if (!$log_master) return false;
+    if (!$whisper) {
+        $log = read_log($past_log, '', '', $datetime, $color_system);
+    } else {
+        $log = read_log($past_log, '', $masterpass, $datetime, $color_system);
+    }
+    if (!$log) return false;
+
+    if (file_exists($past_dir.$filename.".html")) {
+        $filename = $filename. "_". time();
+    }
+
+    $header = html_header('pastlog', '過去ログ '.$filename, false, false);
+    $header2 = html_header('pastlog', '過去ログ [管理用]'.$filename, false, false);
+    $footer = html_footer($copyright);
+
+    $fp = fopen($past_dir.$filename.".html", "w");
+    stream_set_write_buffer($fp, 0);
+    flock($fp,LOCK_EX);
+    fwrite($fp, $header);
+    if ($log) {
+        fwrite($fp, '<div class="com_row">'."\n");
+        foreach ($log as $v) {
+            fwrite($fp, $v."<br>\n");
+        }
+        fwrite($fp, '</div>'."\n");
+    }
+    fwrite($fp, '<hr>');
+    fwrite($fp, $footer);
+    fflush($fp);
+    fclose($fp);
+
+    $fp2 = fopen($master_past_dir.$filename.".html", "w");
+    stream_set_write_buffer($fp2, 0);
+    flock($fp2,LOCK_EX);
+    fwrite($fp2, $header2);
+    if ($log_master) {
+        fwrite($fp2, '<div class="com_row">'."\n");
+        foreach ($log_master as $v) {
+            fwrite($fp2, $v."<br>\n");
+        }
+        fwrite($fp2, '</div>'."\n");
+    }
+    fwrite($fp2, '<hr>');
+    fwrite($fp2, $footer);
+    fflush($fp2);
+    fclose($fp2);
+
+}
+
+// 過去ログリスト
+function log_list($log_dir) {
+    $dir = opendir($log_dir);
+    while($logfiles = readdir($dir)) {
+        if (!ereg("^\.", $logfiles) && $logfiles != 'index.html') {
+            $array_logfiles[] = '<input type="checkbox" name="filename[]" value="'.$logfiles.'"> <a href="'.$log_dir.$logfiles.'" target="admin_past">'.$logfiles.'</a><br>'."\n";
+        }
+    }
+    closedir($dir);
+
+    if ($array_logfiles) {
+        rsort($array_logfiles);
+        foreach ($array_logfiles as $v) {
+            $list .= $v;
+        }
+    }
+
+    return $list;
+
+}
+
+?>
\ No newline at end of file
diff --git a/pastlog_index.php b/pastlog_index.php
new file mode 100644 (file)
index 0000000..0f6c5c4
--- /dev/null
@@ -0,0 +1,131 @@
+<?php
+/*
+ * Ajax Chat for TRPG ver.1.0
+ * (c)2007 Cake All righ1ts reserved.
+ * Mail : cake_67@users.sourceforge.jp
+ * Home : http://trpgtools-onweb.sourceforge.jp/
+ *
+ * [注意事項他]
+ * 本チャットスクリプトの使用および配布は、BSDライセンスに基づきます。
+ * BSDライセンスの詳細につきましては、添付のライセンス.txtを参照してください。
+ *
+ * BSDライセンス概要&使用上の注意
+ * 1. このスクリプトはフリーソフトです。以下の条件を満たす限りにおいて、使用・改造・再配布(オリジナルおよび改造版の両方とも)は自由です。
+ * 再配布する場合、上記著作権表示、本条件書きおよび第2項・第3項の責任限定規定を必ず含めてください。
+ * 2. 同梱のアイコンはPetite Prier様(http://snow.if.tv/)の素材です。
+      本スクリプトの使用および再配布時にアイコンをそのまま用いる場合は、配布元の規定も遵守してください。
+ * 3. 本スクリプトは無保証です。自己責任で使用してください。このスクリプトを使用したいかなる損害に対しても、作者は一切の責任を負いません。
+ * 4. 設置および使用方法に関する質問は、配布サイトの掲示板にお願いします。ただし、必ず回答できるとは限りません。
+ * メールによる質問は、ご遠慮ください。
+ */
+
+// 設定ファイルの読み込み
+require_once './trpgchat-ini.php';
+
+// HTML出力
+print html_header('index', $title.' 過去ログ', true, true);
+
+?>
+<script type="text/javascript">
+<!--
+function onLoadClick() {
+    if ($("#name").attr("value") && $("#pwd").attr("value")) {
+        $("#last").click();
+    }
+}
+
+function showLog(Obj) {
+    if(Obj.value != ""){\r
+        window.mainframe.location.href = Obj.value;\r
+    }
+}
+//-->
+</script>
+</head>
+<body onload="onLoadClick()">
+<table border="0" cellspacing="3" cellpadding="0" id="user" align="center">
+<tr>
+<td class="nodisplay">
+<form action="./pastlog_main.php" target="mainframe" method="get" name="show" class="show" id="show">
+</td>
+<td>
+<img name="whisper" title="最新ログでは、お名前とパスワードを入力すると、関連する「ささやき」も表示されます。" src="./<?php print $whisper; ?>" align="bottom" hspace="1" vspace="0" border="0"></td>
+<td nowrap>
+お名前:<input type="text" name="name" id="name" value="<?php print $_REQUEST['name'] ?>" size="8" class="inputname" id="name">
+</td>
+<td nowrap>
+パスワード:<input type="password" name="pwd" size="4" class="inputpwd" id="pwd" value="<?php print $_REQUEST['pwd'] ?>">
+</td>
+<td nowrap>
+<input type="submit" id="last" class="btn sub" value="最新のログ">
+</td>
+<td class="nodisplay">
+</form></td>
+</tr>
+</table>
+<table border="0" align="center">
+<tr>
+<td class="nodisplay">
+<form action="<?php print $home; ?>" method="<?php print $method; ?>">
+</td>
+<td>
+<input type="image" class="btn sub" src="<?php print $home_icon; ?>" alt="ホーム" title="ホーム">
+</td>
+<td class="nodisplay">
+</form>
+</td>
+<td class="nodisplay">
+<form name="past" id="past" onsubmit="return false;" action=""></td>
+<td nowrap>
+<select name="logfile">
+<option value="">もっと前のログを見る</option>
+<?php
+if ($dir = opendir($past_dir)) {
+    while($logfiles = readdir($dir)) {
+        if (!ereg("^\.", $logfiles) && $logfiles != 'index.html') {
+            $array_logfiles[] =  "<option value=\"".$past_dir.$logfiles."\">".$logfiles."</option>\n";
+        }
+    }
+    closedir($dir);
+
+    if ($array_logfiles) {
+        rsort($array_logfiles);
+        foreach ($array_logfiles as $v) {
+            $list .= $v;
+        }
+    }
+     print $list;
+}
+?>
+</td>
+<td align="left" nowrap>
+<input type="button" class="btn sub" value="表示" onclick="showLog(this.form.logfile)">
+</select>
+</td>
+<td class="nodisplay">
+</form>
+</td>
+<td class="nodisplay">
+<form action="<?php print $pastlog_maker; ?>" method="<?php print $method; ?>" target="admin">
+</td>
+<td nowrap>
+管理画面:<input type="password" name="admin_pwd" size="4" class="inputpwd" value="">
+</td>
+<td>
+<input type="image" class="btn sub" src="<?php print $admin_icon; ?>">
+</td>
+<td class="nodisplay">
+</form>
+</td>
+</tr></table>
+
+<iframe src="./pastlog_main.php" width="100%" frameborder="1" border="1" allowtransparency="true" scrolling="auto" name="mainframe" class="mainframe" style="height:445px;" id="mainframe"></iframe>
+
+<noscript>
+<p><img src="image/blog_jscript.gif" alt="Javascript" width="80" height="15">過去ログ表示機能は、JavaScript が不可の環境では、一部機能のみ使用可能です</p>
+</noscript>
+
+<?php
+// フッター
+print html_footer($copyright);
+ ?>
\ No newline at end of file
diff --git a/pastlog_main.php b/pastlog_main.php
new file mode 100644 (file)
index 0000000..74af05a
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/*
+ * Ajax Chat for TRPG ver.1.0
+ * (c)2007 Cake All righ1ts reserved.
+ * Mail : cake_67@users.sourceforge.jp
+ * Home : http://trpgtools-onweb.sourceforge.jp/
+ *
+ * [注意事項他]
+ * 本チャットスクリプトの使用および配布は、BSDライセンスに基づきます。
+ * BSDライセンスの詳細につきましては、添付のライセンス.txtを参照してください。
+ *
+ * BSDライセンス概要&使用上の注意
+ * 1. このスクリプトはフリーソフトです。以下の条件を満たす限りにおいて、使用・改造・再配布(オリジナルおよび改造版の両方とも)は自由です。
+ * 再配布する場合、上記著作権表示、本条件書きおよび第2項・第3項の責任限定規定を必ず含めてください。
+ * 2. 同梱のアイコンはPetite Prier様(http://snow.if.tv/)の素材です。
+      本スクリプトの使用および再配布時にアイコンをそのまま用いる場合は、配布元の規定も遵守してください。
+ * 3. 本スクリプトは無保証です。自己責任で使用してください。このスクリプトを使用したいかなる損害に対しても、作者は一切の責任を負いません。
+ * 4. 設置および使用方法に関する質問は、配布サイトの掲示板にお願いします。ただし、必ず回答できるとは限りません。
+ * メールによる質問は、ご遠慮ください。
+ */
+
+// 設定ファイルの読み込み
+require_once './trpgchat-ini.php';
+require_once './pastlog-ini.php';
+
+// HTML出力
+print html_header('main', $title.' 過去ログ', false, true);
+
+?>
+
+</head>
+<body>
+<div class="com_row">
+<?php
+// 受信データの整形
+foreach($_GET as $k => $v) {
+    $data[$k] = htmlspecialchars($v);
+}
+
+if ($masterpass && $data['pwd'] == $masterpass) {
+    $row = read_log($past_log, $masterpass, $masterpass, 'true', $color_system);
+} else {
+    $data['myhash'] = create_hash($data['name'], $data['pwd']);
+    $row = read_log($past_log, $data['myhash'], '', 'true', $color_system);
+
+}
+
+if ($row) {
+    foreach ($row as $v) {
+        print $v."<br>\n";
+    }
+}
+ ?>
+</div>
+
+<?php
+// フッター
+print html_footer('');
+ ?>
\ No newline at end of file
diff --git a/trpgchat-ini.php b/trpgchat-ini.php
new file mode 100644 (file)
index 0000000..11ed9c6
--- /dev/null
@@ -0,0 +1,229 @@
+<?php
+/*
+ * Ajax Chat for TRPG ver.1.0
+ * (c)2007 Cake All righ1ts reserved.
+ * Mail : cake_67@users.sourceforge.jp
+ * Home : http://trpgtools-onweb.sourceforge.jp/
+ *
+ * [注意事項他]
+ * 本チャットスクリプトの使用および配布は、BSDライセンスに基づきます。
+ * BSDライセンスの詳細につきましては、添付のライセンス.txtを参照してください。
+ *
+ * BSDライセンス概要&使用上の注意
+ * 1. このスクリプトはフリーソフトです。以下の条件を満たす限りにおいて、使用・改造・再配布(オリジナルおよび改造版の両方とも)は自由です。
+ * 再配布する場合、上記著作権表示、本条件書きおよび第2項・第3項の責任限定規定を必ず含めてください。
+ * 2. 同梱のアイコンはPetite Prier様(http://snow.if.tv/)の素材です。
+      本スクリプトの使用および再配布時にアイコンをそのまま用いる場合は、配布元の規定も遵守してください。
+ * 3. 本スクリプトは無保証です。自己責任で使用してください。このスクリプトを使用したいかなる損害に対しても、作者は一切の責任を負いません。
+ * 4. 設置および使用方法に関する質問は、配布サイトの掲示板にお願いします。ただし、必ず回答できるとは限りません。
+ * メールによる質問は、ご遠慮ください。
+ */
+
+// 基本設定
+    // チャット名
+$title = 'Ajaxチャット for TRPG';
+
+    // 現在画面に表示する行数
+$max_num= 40;
+
+    // ホームページのURL(返り先)
+$home = 'http://trpgtools-onweb.sourceforge.jp/';
+
+    // 管理者用パスワード
+$masterpass = "password";
+    // 入室前表示(改行のみタグ不要。他はHTMLタグ有効)
+$help = '「ダイス」ヘルプ
+発言欄で[2d6+2*2-3]のように入力してください。
+
+「ささやき」ヘルプ
+「参加者」表示の行で、「ささやき」したい相手の名前をクリックしてください。
+ふきだしアイコンをクリックすると「ささやき」が終了します。
+パスワードを入力していないと、「ささやき」は使えません。
+
+HTMLタグは無効です。
+
+動作確認:IE6.0、FireFox2.0、LunaScape4.1、Opera9.0、Netscape 7.1
+';
+    // メソッド(通常POST。一部レンタルサーバなど、POSTが使えない環境ではGETにしてください。
+    $method = 'GET';
+
+    // 書きこみ禁止IP
+$block_ip = array(
+'66.180.82.','18.241.20.','66.35.255.','128.241.20.',//トレンドマイクロ社ロボットのIPです。ウィルスバスターユーザ二重発言の防止用なので、削除しないでください。
+'192.168.1.1', // 禁止IPはこちらに追加
+);
+
+//ダイス関連
+    // 一度に振れる最大ダイス数(0でダイス不使用;最大数は100です)
+$dice_max = 10;
+    // ダイスボタン設定
+$preset_dice = array(
+    '2D6',
+    '1D6',
+    '3D6',
+    '1D8',
+    '1D20',
+    '1D100',
+);
+    // ダイスメッセージ色
+$dice_color = '7793BF';
+
+
+//表示メッセージなどの設定
+    // ステータス欄デフォルト入力
+$status = '';
+    // ステータス表示色
+$status_color = '777777';
+    // PC欄最大数
+$pc_num = 5;
+    // システム表示名
+$system = 'System';
+    // システム文字色
+$color_system = '7793BF';
+    // 入室時に表示されるメッセージ
+$online_msg = 'さんが入室しました。';
+    // 退室時に表示されるメッセージ
+$offline_msg = 'さんが退室しました。';
+    // 名前入力欄への表示
+$noname = 'お名前';
+
+
+// 画像関連設定
+    // ささやきマーク
+$whisper ='./image/comment_r_b.gif';
+    // ささやき中
+$whisper_off ='./image/key_open.gif';
+    // ささやき解除
+$whisper_on ='./image/key_normal.gif';
+    // ステータス欄表示
+$status_icon ='./image/file_pen_b.gif';
+    // PC欄追加
+$pc_show ='./image/item_move_left.gif';
+    // PC欄削除
+$pc_hide ='./image/item_move_right.gif';
+    // ホームアイコン
+$home_icon ='./image/home_b.gif';
+    // ヘルプアイコン
+$help_icon ='./image/help_b.gif';
+    // リロードアイコン
+$reload_icon ='./image/reload_b.gif';
+    // 管理画面アイコン
+$admin_icon ='./image/property_b.gif';
+    // ダイスアイコン
+$dice_icon ='./image/d6.gif';
+
+// データ取得間隔
+    // オンライン中
+$getdata_on = 2;  //(秒)
+        // ROM中
+$getdata_off = 90; //(秒)
+
+// ファイル名
+    // 最新ログファイル名
+$recent_log = './trpgchat.log';
+    // 過去ログ保管ディレクトリ
+$past_dir = './past/';
+    // 管理用過去ログ保管ディレクトリ
+$master_past_dir = './master_past/';
+    // 直近過去ログファイル名
+$past_log = './trpgchat_past.log';
+    // メンバーチェッカーログファイル名
+$now_member = './member.log';
+    // ログ書き込みスクリプト名
+$writescript = './write.php';
+    // 過去ログ管理スクリプト
+$pastlog_maker = './pastlog.php';
+    // ロックファイル
+$lockfile = 'lock.txt';
+$lockfile2 = 'lock2.txt';
+
+// 文字色カラーコード作成
+$color_code = array("00","55","99","BB","FF");
+
+// 詳細設定:通常は変更しないでください
+mb_language('Japanese');
+mb_http_input('auto');
+mb_http_output('utf8');
+ini_set('mbstring.encoding_translation','On');
+ini_set('mbstring.output_buffering','On');
+ini_set('mbstring.output_hanler','mb_output_handler');
+ini_set('session.use_cookies', '0');
+
+// 著作権とバージョン表示(改変しないでください)
+$copyright = 'Chat for TRPG session ver.1.0  Copyright(c) Cake 2007 All Rights Reserved.<br>
+ * icons:<a href="http://snow.if.tv/" target="_blank">Petite Prier</a> Thanks!';
+
+
+// 共通関数
+/* ヘッター */
+function html_header($window, $title, $js, $no_cache, $color_chart = false) {
+    $header = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">'."\n";
+    $header .= '<html>'."\n";
+    $header .= '<head>'."\n";
+    $header .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'."\n";
+    $header .= '<meta http-equiv="Content-Style-Type" content="text/css" />'."\n";
+    if ($js) {
+        $header .= '<meta http-equiv="Content-Script-Type" content="text/javascript" />'."\n";
+    }
+    if ($no_cache) {
+        $header .= '<meta http-equiv="Pragma" content="no-cache">'."\n";
+        $header .= '<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">'."\n";
+        $header .= '<meta http-equiv="Expires" content="Thu, 01 Feb 2007 00:00:00 GMT">'."\n";
+    }
+    if ($window == 'pastlog') {
+        $header .= '<link rel="stylesheet" type="text/css" href="../trpgchat.css">'."\n";
+    } else {
+        $header .= '<link rel="stylesheet" type="text/css" href="trpgchat.css">'."\n";
+    }
+    if ($window == 'index') {
+        $header .= '<link rel="stylesheet" type="text/css" href="index.css">'."\n";
+    } elseif ($window == 'main') {
+        $header .= '<link rel="stylesheet" type="text/css" href="main.css">'."\n";
+    } elseif ($window == 'pastlog') {
+        $header .= '<link rel="stylesheet" type="text/css" href="../main.css">'."\n";
+    }
+    $header .= '<title>'.$title.'</title>'."\n";
+    if ($js) {
+        $header .= '<script type="text/javascript" src="./lib/jquery.js"></script>'."\n";
+    }
+    if ($color_chart) {
+        $header .= '<script type="text/javascript" src="./lib/farbtastic/farbtastic.js"></script>'."\n";
+        $header .= '<script type="text/javascript" src="./lib/farbtastic/farbtastic.css"></script>'."\n";
+    }
+
+    return $header;
+}
+
+/* フッター */
+function html_footer($copyright) {
+    if ($copyright) $footer = '<p class="copyright">'.$copyright.'</p>'."\n";
+    $footer .= '</body>'."\n";
+    $footer .= '</html>'."\n";
+
+    return $footer;
+}
+
+/* エラー表示 */
+function error($msg) {
+    print html_header(false, 'エラー', false, false);
+    print '</head>'."\n";
+    print '<body>'."\n";
+    print '<font color="red">エラー</font><br>'."\n";
+    print $msg."\n";
+    print  html_footer('');
+    exit;
+}
+
+/* トリップ生成 */
+function create_hash($name,$pwd) {
+    //パスワードがなければ中止
+    if (!$pwd) {
+        return false;
+    }
+    $key = substr(substr($pwd,1,2)."dummy",0,2);
+    $key = strtr($key,':;<=>?@[\]^_`','ABCDEFGabcdef');
+    $pwd = substr(crypt($name, $key), -10);
+
+    return $pwd;
+}
+?>
\ No newline at end of file
diff --git a/trpgchat.css b/trpgchat.css
new file mode 100644 (file)
index 0000000..307aedb
--- /dev/null
@@ -0,0 +1,81 @@
+/* \94­\8c¾\98g\81E\83`\83\83\83b\83g\89ï\98b\97\93\8b¤\92Ê\82Ì\90Ý\92è */\r
+@charset "Shift_JIS";\r
+@import url("index.css");\r
+@import url("main.css");\r
+/* @import url("add.css"); */\r
+\r
+/* \83\81\83C\83\93 */\r
+html {\r
+       font-weight: normal;\r
+}\r
+* {\r
+       font-size: 12px;\r
+}\r
+body{\r
+       color: #000000;\r
+}\r
+\r
+/* \83^\83O\95Ê */\r
+img {\r
+       border: none;\r
+}\r
+\r
+input, textarea, select {\r
+       font-size: 12px;\r
+       background-color: #E0E0E0;\r
+       border-color: #999999;\r
+       border-style: groove;\r
+}\r
+\r
+h1 {\r
+       font-size:xx-large;\r
+}\r
+\r
+h2 {\r
+       font-size:x-large;\r
+}\r
+\r
+h3 {\r
+       font-size:large;\r
+}\r
+\r
+h4 {\r
+       font-size:medium;\r
+}\r
+\r
+h5 {\r
+       font-size:small;\r
+}\r
+\r
+h6 {\r
+       font-size:x-small;\r
+}\r
+\r
+\r
+a:link {\r
+       color: #6C00D9 !important;\r
+}\r
+a:visited {\r
+       color: #0000a0 !important;\r
+}\r
+a:hover {\r
+       color: #F9C448 !important;\r
+       text-decoration: none !important;\r
+}\r
+\r
+/* \97p\93r\95Ê */\r
+.help {\r
+}\r
+\r
+.caution {\r
+       font-weight: bold;\r
+       color: #ff0000;\r
+}\r
+\r
+.copyright{\r
+       font-size: 10px;\r
+       text-align: center;\r
+}\r
+\r
+\r
+/* \8cÂ\95Ê */\r
diff --git a/trpgchat.log b/trpgchat.log
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/trpgchat_past.log b/trpgchat_past.log
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/write.php b/write.php
new file mode 100644 (file)
index 0000000..5eac5c7
--- /dev/null
+++ b/write.php
@@ -0,0 +1,242 @@
+<?php
+/*
+ * Ajax Chat for TRPG ver.1.0
+ * (c)2007 Cake All righ1ts reserved.
+ * Mail : cake_67@users.sourceforge.jp
+ * Home : http://trpgtools-onweb.sourceforge.jp/
+ *
+ * [注意事項他]
+ * 本チャットスクリプトの使用および配布は、BSDライセンスに基づきます。
+ * BSDライセンスの詳細につきましては、添付のライセンス.txtを参照してください。
+ *
+ * BSDライセンス概要&使用上の注意
+ * 1. このスクリプトはフリーソフトです。以下の条件を満たす限りにおいて、使用・改造・再配布(オリジナルおよび改造版の両方とも)は自由です。
+ * 再配布する場合、上記著作権表示、本条件書きおよび第2項・第3項の責任限定規定を必ず含めてください。
+ * 2. 同梱のアイコンはPetite Prier様(http://snow.if.tv/)の素材です。
+      本スクリプトの使用および再配布時にアイコンをそのまま用いる場合は、配布元の規定も遵守してください。
+ * 3. 本スクリプトは無保証です。自己責任で使用してください。このスクリプトを使用したいかなる損害に対しても、作者は一切の責任を負いません。
+ * 4. 設置および使用方法に関する質問は、配布サイトの掲示板にお願いします。ただし、必ず回答できるとは限りません。
+ * メールによる質問は、ご遠慮ください。
+ */
+
+// 設定ファイルの読み込み
+require_once 'trpgchat-ini.php';
+//メンバーチェッカー
+require_once 'member_check.php';
+
+// ユーザの情報
+$host = gethostbyaddr($_SERVER['REMOTE_ADDR']);
+
+// IPブロック
+foreach ($block_ip as $v) {
+    if (strstr($host, $v)) { die("書きこみできません。"); }
+}
+
+// ファイルロック
+$lfp = fopen($lockfile,"w");
+stream_set_write_buffer($lfp, 0);
+flock($lfp,LOCK_EX);
+
+// 既存ファイル内容の格納
+$log = array();
+$log[] = file($recent_log);
+
+// 受信データの整形
+foreach($_GET as $k => $v) {
+    $data[$k] = htmlspecialchars($v);
+}
+
+    // PC名がない場合PL名
+if (!$data['c']) $data['c'] = $data['n'];
+
+$ua = getenv("HTTP_USER_AGENT");
+
+    // コメント本文の処理:(予定)ダイス、カード、タグ有効[b,span,i,u]、オートリンク、禁止語句処理など
+        // ダイス
+if ($dice_max) {
+    if(preg_match("/(.*)[[]\({0,}([0-9]{1,3})([dD])([0-9]{1,3})([-\+\*\/0-9\s]{0,}[\]])(.*$)/i", $data['m'], $dice)) {
+        $dice_result = dice_convert($dice[2], $dice[4], $dice[5], $dice_max, $dice_color);
+        $data['m'] = $dice[1].$dice_result.$dice[6];
+    }
+}
+
+// 既存ログのチェック
+if(!is_array($log)){
+    $log = array();
+} else {
+    $stopflag=0;
+    foreach ($log[0] as $k => $v){
+        $temp[$k] = explode("<>", $v);
+    }
+}
+
+// 書込み
+if($stopflag==0) {
+
+    // 最新ログNO
+    if ($temp[0][0]) {
+        $last_id = $temp[0][0]+1;
+    } else {
+        $last_id = 1;
+    }
+
+    // 書き込み整形
+    $write = "";
+        // ログイン
+    if ($data['y'] =='in') {
+        $pcname = $system;
+        $data['m'] = $data['n'].$online_msg;
+        $data['l'] = $color_system;
+        $data['s'] = 0;
+        // ログアウト
+    } elseif ($data['y'] == 'out') {
+        $pcname = $system;
+        $data['m'] = $data['n'].$offline_msg;
+        $data['l'] = $color_system;
+        $data['s'] = 0;
+    } else {
+        $pcname = $data['c'];
+    }
+
+    if ($data['n'] && $data['p']) {
+        $pwd = create_hash($data['n'],$data['p']);
+    }
+
+    $write = $last_id."<>".$data['n']."<>".$pcname."<>".$data['l']."<>".$data['m']."<>".time()."<>".$host."<>".$ua."<>".$pwd."<>".$data['w']."<>".$data['h']."<>".$data['s']."<>".$data['t']."<>".$data['a']."\n";
+
+    array_unshift($log[0], $write);
+
+    //最大行数を超えていたら最終行を削除
+    if (count($log[0]) >= $max_num) {
+        array_pop($log[0]);
+    }
+
+    // ログファイル更新
+    $fp = @fopen($recent_log, "w+") or die("ログファイルを開けません。");
+    //$bom = "\xef\xbb\xbf";
+    //fwrite($fp, $bom);
+
+        foreach($log[0] as $k => $v) {
+            fwrite($fp, $v);
+        }
+    fclose($fp);
+}
+
+    //直近の過去ログ更新
+    write_recent_past($write, $past_log);
+
+    // ロック解除
+fflush($lfp);
+fclose($lfp);
+
+    //参加者チェッカーに書き込み
+member_checker($data['n'], $pwd, $data['y'], $now_member, $getdata_off);
+
+1;
+
+
+/**** ここから関数 ****/
+
+// 直近の過去ログ
+function write_recent_past($write, $pdata) {
+    $pfp = @fopen($pdata, "a+") or die("過去ログファイルを開けません。");
+
+    fwrite($pfp, $write);
+
+    return true;
+}
+
+function dice_convert($dicenum, $dicenumber, $revision, $dice_max, $color) {
+
+    // ダイス本体
+    if($dicenum >= 1 && $dicenum <= $dice_max) {
+        if ($dicenumber >= 1 && $dicenumber <= 100) {
+            mt_srand((double) microtime() * 1000000);
+            $dicesum = 0;
+            for ($i=0; $i<$dicenum; $i++) {
+                $d_result[$i] = mt_rand(1,$dicenumber);
+                $dice_sum += $d_result[$i];
+                if ($i != 0) {
+                    $dice_list .= ", ".$d_result[$i];
+                } else {
+                    $dice_list = " (".$d_result[$i];
+                }
+            }
+            $dice_list .= ")";
+        } else {
+            return $dice.' (d2~d100の範囲で指定してください)';
+        }
+    } else {
+        return $dice.' (ダイスの数は1から'.$dice_max.'の間で指定してください)';
+    }
+
+    // 修正値を加えた結果の計算
+    if(rtrim($revision, "]")) {
+        $dice = preg_replace("/\s/","+",$dice);
+        $value = calc_value($dice_sum, $revision);
+    } else {
+        $value = $dice_sum;
+    }
+
+    if (!is_numeric($value)) {
+        return '<span style="color:#'.$color.';">'.$dice.' ('.$value.')</span>';
+    } else {
+        $dice = '<span style="color:#'.$color.'; font-weight: bold;">['.$dicenum.'d'.$dicenumber.$revision.' :'.$dice_list.' = '.$value.'</span>';
+        return $dice;
+    }
+}
+
+/* ダイス修正値の計算
+ */
+function calc_value($dice_sum, $revision) {
+    $multi = preg_match("/\*/", $revision);
+    $dev = preg_match("/\//", $revision);
+    $add = preg_match("/\+/", $revision);
+    $subtract = preg_match("/\-/", $revision);
+
+    // +-*/で分割
+    $revision = preg_replace("/\+/","<>+<>",$revision);
+    $revision = preg_replace("/\-/","<>-<>",$revision);
+    $revision = preg_replace("/\*/","<>*<>",$revision);
+    $revision = preg_replace("/\//","<>/<>",$revision);
+    $parts = explode("<>",$revision);
+    array_splice($parts, 0, 1, $dice_sum);
+
+    // 乗算&除算
+    if ($multi || $dev) {
+        foreach ($parts as $k => $v) {
+            if ($v != '0' && $v == '*') {
+                if (!preg_match("/[0-9]{1,}/", $parts[$k+1])) return "演算子が連続してます";
+                $flg = $k;
+                array_splice($parts, $k+1, 1, $parts[$k-1] * $parts[$k+1]);
+                array_splice($parts, $k-1, 1, 0);
+                array_splice($parts, $k, 1, $parts[$k-2]);
+                array_splice($parts, $k-2, 1, '+');
+            }
+            if ($v != '0' && $v == '/') {
+                if (!preg_match("/[0-9]{1,}/", $parts[$k+1])) return "演算子が連続してます";
+                array_splice($parts, $k+1, 1, $parts[$k-1] / $parts[$k+1]);
+                array_splice($parts, $k-1, 1, 0);
+                array_splice($parts, $k, 1, $parts[$k-2]);
+                array_splice($parts, $k-2, 1, '+');
+            }
+        }
+    }
+
+    // 加減算
+        foreach ($parts as $k => $v){
+            if ($v != '0') {
+                if ($v == '+') {
+                    if (!preg_match("/[0-9]{1,}/", $parts[$k+1]))  return "演算子が連続してます";
+                    array_splice($parts, 0, 1, $parts[0] + $parts[$k+1]);
+                } elseif ($v == '-') {
+                    if (!preg_match("/[0-9]{1,}/", $parts[$k+1]))  return "演算子が連続してます";
+                    array_splice($parts, 0, 1, $parts[0] - $parts[$k+1]);
+                }
+            }
+        }
+
+    return round($parts[0], 1);
+}
+
+ ?>
\ No newline at end of file
diff --git a/ドキュメント/LICENSE.txt b/ドキュメント/LICENSE.txt
new file mode 100644 (file)
index 0000000..c39f5d2
--- /dev/null
@@ -0,0 +1,11 @@
+Ajax Chat for TRPG\r
+\r
+Copyright (c) 2007, Cake All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\r
+\r
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\r
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\r
+    * Neither the name of the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/ドキュメント/README.txt b/ドキュメント/README.txt
new file mode 100644 (file)
index 0000000..f3606d6
--- /dev/null
@@ -0,0 +1,68 @@
+=======================================================================================\r
+Ajax Chat for TRPG ver.1.0\r
+(c)2007 Cake All rights reserved.\r
+Mail :  cake_67@users.sourceforge.jp\r
+Home : http://trpgtools-onweb.sourceforge.jp/\r
+\r
+---------------------------------------------------------------------------------\r
+[\92\8d\88Ó\8e\96\8d\80\91¼]\r
+\96{\83`\83\83\83b\83g\83X\83N\83\8a\83v\83g\82Ì\8eg\97p\82¨\82æ\82Ñ\94z\95z\82Í\81ABSD\83\89\83C\83Z\83\93\83X\82É\8aî\82Ã\82«\82Ü\82·\81B\r
+BSD\83\89\83C\83Z\83\93\83X\82Ì\8fÚ\8d×\82É\82Â\82«\82Ü\82µ\82Ä\82Í\81A\93Y\95t\82Ì\83\89\83C\83Z\83\93\83X.txt\82ð\8eQ\8fÆ\82µ\82Ä\82­\82¾\82³\82¢\81B\r
+\r
+BSD\83\89\83C\83Z\83\93\83X\8aT\97v\81\95\8eg\97p\8fã\82Ì\92\8d\88Ó\r
+1. \82±\82Ì\83X\83N\83\8a\83v\83g\82Í\83t\83\8a\81[\83\\83t\83g\82Å\82·\81B\88È\89º\82Ì\8fð\8c\8f\82ð\96\9e\82½\82·\8cÀ\82è\82É\82¨\82¢\82Ä\81A\8eg\97p\81E\89ü\91¢\81E\8dÄ\94z\95z\81i\83I\83\8a\83W\83i\83\8b\82¨\82æ\82Ñ\89ü\91¢\94Å\82Ì\97¼\95û\82Æ\82à\81j\82Í\8e©\97R\82Å\82·\81B\r
+\81@\8dÄ\94z\95z\82·\82é\8fê\8d\87\81A\8fã\8bL\92\98\8dì\8c \95\\8e¦\81A\96{\8fð\8c\8f\8f\91\82«\82¨\82æ\82Ñ\91æ2\8d\80\81E\91æ3\8d\80\82Ì\90Ó\94C\8cÀ\92è\8bK\92è\82ð\95K\82¸\8aÜ\82ß\82Ä\82­\82¾\82³\82¢\81B\r
+2. \96{\83X\83N\83\8a\83v\83g\82ÍjQuery(http://www.jquery.com/)\82ð\97p\82¢\82Ä\82¢\82Ü\82·\81B\r
+   \93¯\8d«\82Ì\83A\83C\83R\83\93\82ÍPetite Prier\97l(http://snow.if.tv/)\82Ì\91f\8dÞ\82Å\82·\81B\r
+   \96{\83X\83N\83\8a\83v\83g\82Ì\8eg\97p\82¨\82æ\82Ñ\8dÄ\94z\95z\8e\9e\82ÉjQuery\81A\83A\83C\83R\83\93\82ð\82»\82Ì\82Ü\82Ü\97p\82¢\82é\8fê\8d\87\82Í\81A\94z\95z\8c³\82Ì\8bK\92è\82à\8f\85\8eç\82µ\82Ä\82­\82¾\82³\82¢\81B\r
+3. \96{\83X\83N\83\8a\83v\83g\82Í\96³\95Û\8fØ\82Å\82·\81B\8e©\8cÈ\90Ó\94C\82Å\8eg\97p\82µ\82Ä\82­\82¾\82³\82¢\81B\82±\82Ì\83X\83N\83\8a\83v\83g\82ð\8eg\97p\82µ\82½\82¢\82©\82È\82é\91¹\8aQ\82É\91Î\82µ\82Ä\82à\81A\8dì\8eÒ\82Í\88ê\90Ø\82Ì\90Ó\94C\82ð\95\89\82¢\82Ü\82¹\82ñ\81B\r
+4. \90Ý\92u\82¨\82æ\82Ñ\8eg\97p\95û\96@\82É\8aÖ\82·\82é\8e¿\96â\82Í\81A\94z\95z\83T\83C\83g\82Ì\8cf\8e¦\94Â\82É\82¨\8aè\82¢\82µ\82Ü\82·\81B\82½\82¾\82µ\81A\95K\82¸\89ñ\93\9a\82Å\82«\82é\82Æ\82Í\8cÀ\82è\82Ü\82¹\82ñ\81B\r
+\83\81\81[\83\8b\82É\82æ\82é\8e¿\96â\82Í\81A\82²\89\93\97\82­\82¾\82³\82¢\81B\r
+---------------------------------------------------------------------------------\r
+[\90Ý\92u\95û\96@]\r
+\89ð\93\80\82µ\82½\83f\83B\83\8c\83N\83g\83\8a\8aÜ\82Ü\82ê\82é\83T\83u\83f\83B\83\8c\83N\83g\83\8a\81A\83t\83@\83C\83\8b\82ð\81AWeb\83T\81[\83o\8fã\82É\88È\89º\82Ì\82æ\82¤\82É\90Ý\92u\82µ\82Ä\82­\82¾\82³\82¢\81B\r
+\r
+\84\9f\84¢\r
+  \84¥ image [644]\r
+  \84¥ lib [644]\r
+  \84¥ master_past [777]\r
+  \84¥ past [777]\r
+  \84¥ index.css [644]\r
+  \84¥ index.php [644]\r
+  \84¥ lock.txt [666]\r
+  \84¥ lock2.txt [666]\r
+  \84¥ main.css [644]\r
+  \84¥ main.php [644]\r
+  \84¥ master_pastlog.php [644]\r
+  \84¥ member.log [666]\r
+  \84¥ member_check.php [644]\r
+  \84¥ pastlog_index.php [644]\r
+  \84¥ pastlog_main.php [644]\r
+  \84¥ pastlog-ini.php [644]\r
+  \84¥ trpgchat.css [644]\r
+  \84¥ trpgchat.log [666]\r
+  \84¥ trpgchat_past.log [666]\r
+  \84¥ trpgchat-ini.php [644]\r
+  \84¤ write.php [644]\r
+\r
+\81\96[]\93à\82Ì\90\94\8e\9a\82Í\83p\81[\83~\83b\83V\83\87\83\93\82Ì\88ê\97á\82Å\82·\81B\8aÂ\8b«\82É\8d\87\82í\82¹\82Ä\93K\90Ø\82È\92l\82É\93Ç\82Ý\91Ö\82¦\82Ä\82­\82¾\82³\82¢\81B\r
+\r
+\r
+trpgchat-ini.php\82Ì\93à\97e\82ð\81A\8aÂ\8b«\82É\89\9e\82\82Ä\8f\91\82«\8a·\82¦\82Ä\82­\82¾\82³\82¢\81B\r
+\93Á\82É\81A\95K\82¸\95Ï\8dX\82·\82×\82«\89Ó\8f\8a\82Í\88È\89º\82Ì3\89Ó\8f\8a\82Å\82·\81B\r
+\r
+// \8aî\96{\90Ý\92è\r
+    // \83`\83\83\83b\83g\96¼\r
+$title = 'Ajax\83`\83\83\83b\83g for TRPG';\r
+\r
+    // \83z\81[\83\80\83y\81[\83W\82ÌURL(\95Ô\82è\90æ\81j\r
+$home = 'http://trpgtools-onweb.sourceforge.jp/';\r
+\r
+    // \8aÇ\97\9d\8eÒ\97p\83p\83X\83\8f\81[\83h\r
+$masterpass = "SFsample";\r
+---------------------------------------------------------------------------------\r
+[\8dX\90V\97\9a\97ð]\r
+\r
+---------------------------------------------------------------------------------\r
+2007.06.01\r
+Written by Cake\r
diff --git a/ドキュメント/ライセンス.txt b/ドキュメント/ライセンス.txt
new file mode 100644 (file)
index 0000000..88f3f89
--- /dev/null
@@ -0,0 +1,10 @@
+Ajax\83`\83\83\83b\83g for TRPG\r
+Copyright (c) 2007, Cake All rights reserved.\r
+\r
+\83\\81[\83X\83R\81[\83h\8c`\8e®\82©\83o\83C\83i\83\8a\8c`\8e®\82©\81A\95Ï\8dX\82·\82é\82©\82µ\82È\82¢\82©\82ð\96â\82í\82¸\81A\88È\89º\82Ì\8fð\8c\8f\82ð\96\9e\82½\82·\8fê\8d\87\82É\8cÀ\82è\81A\8dÄ\94Ð\95z\82¨\82æ\82Ñ\8eg\97p\82ª\8b\96\89Â\82³\82ê\82Ü\82·\81B\r
+\r
+    * \83\\81[\83X\83R\81[\83h\82ð\8dÄ\94Ð\95z\82·\82é\8fê\8d\87\81A\8fã\8bL\82Ì\92\98\8dì\8c \95\\8e¦\81A\96{\8fð\8c\8f\88ê\97\97\81A\82¨\82æ\82Ñ\89º\8bL\96Æ\90Ó\8fð\8d\80\82ð\8aÜ\82ß\82é\82±\82Æ\81B\r
+    * \83o\83C\83i\83\8a\8c`\8e®\82Å\8dÄ\94Ð\95z\82·\82é\8fê\8d\87\81A\94Ð\95z\95¨\82É\95t\91®\82Ì\83h\83L\83\85\83\81\83\93\83g\93\99\82Ì\8e\91\97¿\82É\81A\8fã\8bL\82Ì\92\98\8dì\8c \95\\8e¦\81A\96{\8fð\8c\8f\88ê\97\97\81A\82¨\82æ\82Ñ\89º\8bL\96Æ\90Ó\8fð\8d\80\82ð\8aÜ\82ß\82é\82±\82Æ\81B\r
+    * \8f\91\96Ê\82É\82æ\82é\93Á\95Ê\82Ì\8b\96\89Â\82È\82µ\82É\81A\96{\83\\83t\83g\83E\83F\83A\82©\82ç\94h\90\82µ\82½\90»\95i\82Ì\90é\93`\82Ü\82½\82Í\94Ì\94\84\91£\90i\82É\81A<\91g\90D>\82Ì\96¼\91O\82Ü\82½\82Í\83R\83\93\83g\83\8a\83r\83\85\81[\83^\81[\82Ì\96¼\91O\82ð\8eg\97p\82µ\82Ä\82Í\82È\82ç\82È\82¢\81B\r
+\r
+\96{\83\\83t\83g\83E\83F\83A\82Í\81A\92\98\8dì\8c \8eÒ\82¨\82æ\82Ñ\83R\83\93\83g\83\8a\83r\83\85\81[\83^\81[\82É\82æ\82Á\82Ä\81u\8c»\8fó\82Ì\82Ü\82Ü\81v\92ñ\8b\9f\82³\82ê\82Ä\82¨\82è\81A\96¾\8e¦\96Ù\8e¦\82ð\96â\82í\82¸\81A\8f¤\8bÆ\93I\82È\8eg\97p\89Â\94\\90«\81A\82¨\82æ\82Ñ\93Á\92è\82Ì\96Ú\93I\82É\91Î\82·\82é\93K\8d\87\90«\82É\8aÖ\82·\82é\88Ã\96Ù\82Ì\95Û\8fØ\82à\8aÜ\82ß\81A\82Ü\82½\82»\82ê\82É\8cÀ\92è\82³\82ê\82È\82¢\81A\82¢\82©\82È\82é\95Û\8fØ\82à\82 \82è\82Ü\82¹\82ñ\81B\92\98\8dì\8c \8eÒ\82à\83R\83\93\83g\83\8a\83r\83\85\81[\83^\81[\82à\81A\8e\96\97R\82Ì\82¢\82©\82ñ\82ð\96â\82í\82¸\81A\91¹\8aQ\94­\90\82Ì\8c´\88ö\82¢\82©\82ñ\82ð\96â\82í\82¸\81A\82©\82Â\90Ó\94C\82Ì\8dª\8b\92\82ª\8c_\96ñ\82Å\82 \82é\82©\8cµ\8ai\90Ó\94C\82Å\82 \82é\82©\81i\89ß\8e¸\82»\82Ì\91¼\82Ì\81j\95s\96@\8ds\88×\82Å\82 \82é\82©\82ð\96â\82í\82¸\81A\89¼\82É\82»\82Ì\82æ\82¤\82È\91¹\8aQ\82ª\94­\90\82·\82é\89Â\94\\90«\82ð\92m\82ç\82³\82ê\82Ä\82¢\82½\82Æ\82µ\82Ä\82à\81A\96{\83\\83t\83g\83E\83F\83A\82Ì\8eg\97p\82É\82æ\82Á\82Ä\94­\90\82µ\82½\81i\91ã\91Ö\95i\82Ü\82½\82Í\91ã\97p\83T\81[\83r\83X\82Ì\92²\92B\81A\8eg\97p\82Ì\91r\8e¸\81A\83f\81[\83^\82Ì\91r\8e¸\81A\97\98\89v\82Ì\91r\8e¸\81A\8bÆ\96±\82Ì\92\86\92f\82à\8aÜ\82ß\81A\82Ü\82½\82»\82ê\82É\8cÀ\92è\82³\82ê\82È\82¢\81j\92¼\90Ú\91¹\8aQ\81A\8aÔ\90Ú\91¹\8aQ\81A\8bô\94­\93I\82È\91¹\8aQ\81A\93Á\95Ê\91¹\8aQ\81A\92¦\94±\93I\91¹\8aQ\81A\82Ü\82½\82Í\8c\8b\89Ê\91¹\8aQ\82É\82Â\82¢\82Ä\81A\88ê\90Ø\90Ó\94C\82ð\95\89\82í\82È\82¢\82à\82Ì\82Æ\82µ\82Ü\82·\81B
\ No newline at end of file