#!/usr/bin/perl
#
######################################################################
###
###
###  CGI投票システム T-Vote Ver.7.01
###     [1/1] 本体 (tvote.cgi)
###                                 (c) 1996-1999 Takahiro Nishida
###                                 http://www.mytools.net/
###
###
######################################################################
#
### 変数設定部 （詳細は上記ページをご覧下さい） ######################

$ext = "cgi";
$basedir = ".";
$method = "post";
$code = "sjis";
$password = "AiYuukiKibou";
$admin_email = "rero2\@yuumu.org";

### 変数設定部 （ここまで）###########################################

require "./jcode.pl";

$verno = '7.01';
$lockfile="$basedir/lockdir/tv7.lock";

print "Content-type: text/html\n\n";

&main;

print "\n";



##### メイン関数
sub main{
	&lock;
	&check_input;
	&open_datafile;
	&exec_admin;
	&check_right;
	&add_point;
	&add_datas;
	&show_html;
	&update_datafile;
	&unlock;
}



##### 入力のチェック
sub check_input{
	if ($ENV{'REQUEST_METHOD'} eq "POST") {
		read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
	}
	else {
		$buffer = $ENV{'QUERY_STRING'};
	}
	@pairs = split(/&/, $buffer);
	foreach $pair (@pairs) {
		($vn, $value) = split(/=/, $pair);
		$FORM{$vn} = &decode($value);
	}
	
	$event = $FORM{'event'};
	$item = $FORM{'item2'} || $FORM{'item1'};
	$show = $FORM{'show'};
	$com = $FORM{'com'};
	$pwd = $FORM{'pwd'};
	$sid = $FORM{'sid'};
	$add = $FORM{'add'};
	$act = $FORM{'act'};
	
	($event =~ /^\w+$/) || &error(4);
	
	$user_ip = $ENV{'REMOTE_ADDR'};
	$user_host = $ENV{'REMOTE_HOST'} || $user_ip;
	$time_sec = time();
	$new_sid = $time_sec;
	
	# 拡大表示の対象(初期値)
	$insert_point = 0;
}



##### データファイルのオープン
sub open_datafile{
	$datafile = "$basedir/$event.txt";
	$tpfile = "$basedir/$event.html";
	$logfile = "$basedir/$event.log";
	$comfile = "$basedir/$event.com";
	$rightfile = "$basedir/$event.rgt";
	$admtpfile = "$basedir/tvadmin.tp";
	$acomfile = "$basedir/allcom_$event.html";
	
	&openfile($tpfile, *tps);
	&openfile($datafile, *datas, 1);
	&openfile($rightfile, *rights, 1);
	
	unless($act){
		&openfile($logfile, *logs, 1);
		&openfile($comfile, *coms, 1);
	}
	else{
		&openfile($admtpfile, *atps);
	}
	
	### Ver.6 → Ver.7 バージョンアップ用
	unless($datas[0] =~ /^\d+\t\d+\t\d+\t/){
		unshift(@datas, "1\t20\t0\t10\t10\t-1\t5\t#FFFFFF\t#000000\t#FFCCCC\t#DD0000\t400\t\n");
		$upf_data = 1;
	}

	### コンフィグ行の取得
	$configline = shift(@datas);
	($inew, $icom, $ircom, $ilog, $ishow, $iltime, $ilnum, $nback, $nfont, $eback, $efont, $igraph) = split("\t", $configline);
}



########## 管理関数 ここから ##########
##### 管理モードの実行
sub exec_admin{
	($pwd eq $password) || return;
	
	($act) || &error(5, "作業が選択されていません。");
	
	if($FORM{'admitem'}){
		$mode = "admitem";
		($act =~ /^d/) && &fix_data;
	}
	elsif($FORM{'admcfg'}){
		$mode = "admcfg";
		($act eq "fix") && &fix_config;
	}
	($admmsg) || ($admmsg = "$event の管理用フォームを開きました。");
}

##### 項目の修正
sub fix_data{
	local($an, $ai, $vn, $i, $bitem, $bvalue);
	
	$an = $FORM{'an'};
	$ai = $FORM{'ai'};
	$vn = $FORM{'vn'};
	
	($act eq 'ddel') || ($vn =~ /^\d+$/) || (&error(5, "票数が不正です。"));
	
	# 新規だったら入力項目を有効に
	($act eq 'dnew') && (($ai = $an) || &error(5, "新規項目が記述されていません。"));
	
	# 重複チェック
	push(@datas, "$ai\t-1"); # ダミー行
	for (0..$#datas){
		($bitem, $bvalue) = split("\t", $datas[$_]);
		if($bitem eq $ai){
			$i = $_;
			last;
		}
	}
	
	# 削除
	if($act eq 'ddel' || $act eq 'dfix'){
		($i < $#datas) || &error(5, "指定された項目は存在しません。");
		splice(@datas, $i, 1);
		$admmsg = "$event の項目 $ai を削除しました。";
	}
	
	# 追加
	if($act eq 'dfix' || $act eq 'dnew'){
		for (0..$#datas){
			($bitem, $bvalue) = split("\t", $datas[$_]);
			if($bvalue < $vn){
				splice(@datas, $_, 0, "$ai\t$vn\t\n");
				last;
			}
		}
		$admmsg = "$event の項目 $ai を $vn 票に修正しました。";
	}
	pop(@datas);
	
	# 新規のチェック
	if($act eq 'dnew'){
		($i == $#datas) || &error(5, "指定された項目は既に存在しています。$i, $#datas");
		$admmsg = "$event の項目 $ai を $vn 票で新規追加しました。";
	}
	
	$upf_data = 1;
}



##### 設定の変更
sub fix_config{
	# 制限時間のみあらかじめ値を取得
	$piltime = $iltime;
	
	### 入力の受け取り
	$inew = $FORM{'fnew'};
	$icom = $FORM{'fcom'};
	$ircom = $FORM{'frcom'};
	$ilog = $FORM{'flog'};
	$ishow = $FORM{'fshow'};
	$iltime = $FORM{'fltime'};
	$ilnum = $FORM{'flnum'};
	$nback = $FORM{'fnback'};
	$nfont = $FORM{'fnfont'};
	$eback = $FORM{'feback'};
	$efont = $FORM{'fefont'};
	$igraph = $FORM{'fgraph'};
	
	### 妥当性チェック
	($inew =~ /^[01]$/) || &error(5, "【項目追加】 の値が不正です。（$inew）");
	($icom =~ /^\d+$/) || &error(5, "【コメント表\示】 の値が不正です。（$icom）");
	($ircom =~ /^\d+$/) || &error(5, "【コメント保存】 の値が不正です。（$ircom）");
	($ilog =~ /^\d+$/) || &error(5, "【ログ表\示】 の値が不正です。（$ilog）");
	($ishow > 0) || &error(5, "【初期表\示】 の値が不正です。（$ishow）");
	($iltime =~ /^-?\d+(\.\d+)?$/) || &error(5, "【投票制限】 の値が不正です。（$iltime）");
	($ilnum =~ /^\d+$/) || &error(5, "【投票制限】 の値が不正です。（$ilnum）");
	($igraph =~ /^\d+$/) || &error(5, "【グラフ】 の値が不正です。（$igraph）");
	
	### 標準の配色に戻す
	if($FORM{'initcolor'}){
		$nback = "#FFFFFF";
		$nfont = "#000000";
		$eback = "#FFCCCC";
		$efont = "#DD0000";
	}
	
	### コメント全保存ファイルのクリア
	($FORM{'clearallcom'}) && &updatefile($acomfile);
	
	### 制限時間が変わっていたら権利ファイルを初期化
	($piltime == $iltime) || ($rights[0] = 0);
	
	$configline = "$inew\t$icom\t$ircom\t$ilog\t$ishow\t$iltime\t$ilnum\t$nback\t$nfont\t$eback\t$efont\t$igraph\t\n";
	$upf_data = 1;
	
	$admmsg = "$event の設定を変更しました。($piltime, $iltime)";
}

########## 管理関数 ここまで ##########



##### 権利のチェック
sub check_right{
	### 無制限なら無視
	($iltime < 0) && return;
	
	chop($rights[0]); # 改行を切り落とす
	# 初期化（一番近い０時）
	$rtime = ($rights[0]) || ($time_sec - ($time_sec + 32400) % 86400);
	
	# 一生でないなら時間のチェック
	if(($iltime > 0) && ($rtime < $time_sec)){
		while($rtime < $time_sec){
			$rtime += 3600 * $iltime;
		}
		$rights[0] = $rtime . "\n";
		$#rights = 0;
		$upf_right = 1;
	}
	# 投票済み項目
	foreach (@rights){
		(/$user_ip\t/) && push(@uright, $_);
	}
	# 残り権利数
	$vrlest = $ilnum - @uright;
	
	# 投票があった場合、権利のチェック
	if($item && $add){
		(--$vrlest >= 0) || &error(6);
		push(@rights, "$user_ip\t$item\t\n");
		push(@uright, "$user_ip\t$item\t\n");
		$rights[0] = $rtime . "\n";
		$upf_right = 1;
	}
}



##### 票数を加える
sub add_point{
	($item && $add) || return;
	
	local($i, $bitem, $bvalue, $value_of_point);
	$value_of_point = (split("\t",$datas[0]))[1];
	
	$i = 0;
	push(@datas, "$item\t0\t\n"); # ダミー行
	foreach (@datas){
		($bitem, $bvalue) = split("\t");
		if($value_of_point > $bvalue){
			$insert_point = $i; # 票の変わり目の場所と票数を記録
			$value_of_point = $bvalue;
		}
		if($bitem eq $item){
			splice(@datas, $i, 1);
			$bvalue++;
			($bvalue < $value_of_point) && ($insert_point = $i); # 追いつかなかったら同じ場所
			splice(@datas, $insert_point, 0, "$bitem\t$bvalue\t\n");
			last;
		}
		$i++;
	}
	
	# 新しい項目だった場合
	if($i == $#datas){
		($inew) || &error(7);
		$flag_new = 1;
	}
	else{
		pop(@datas); # ダミー行の削除
	}
	
	$upf_data = 1;
}



##### 票数以外のデータの書換
sub add_datas{
	($item && $add) || return;
	
	local($date, $newline, $bnew);
	$date = &get_time($time_sec);
	
	### ログ
	($flag_new) && ($bnew .= "[NEW]");
	$newline = "<LI><NOBR>$date <B>$item</B> <I>($user_host)</I> $bnew </NOBR>\n";
	unshift(@logs, $newline);
	(@logs <= $ilog) || ($#logs = $ilog - 1);
	$upf_log = 1;
	
	### コメント
	if($icom && $com){
		$newline = "<!--$sid--><LI>$date <B>$item</B> <I>($user_host)</I><BR>...$com\n";
		($coms[0] =~ /--$sid--/) && &error(9); # 連続コメント防止
		unshift(@coms, $newline);
		(@coms <= $icom) || ($#coms = $icom - 1);
		$upf_com = 1;
		
		# 全コメント保存の場合（ちょっと処理が汚い。。。）
		($ircom) && &updatefile($acomfile, "", $newline, 1);
	}
}



##### ファイルの更新
sub update_datafile{
	unshift(@datas, $configline); # コンフィグ行を戻す
	($upf_data) && &updatefile($datafile, *datas);
	($upf_log) && &updatefile($logfile, *logs);
	($upf_com) && &updatefile($comfile, *coms);
	($upf_right) && &updatefile($rightfile, *rights);
}





#################### ＨＴＭＬ表示関数　ここから ####################

##### メイン
sub show_html{
	local($htmlbuf);
	
	### 選択項目（管理でも使用する）
	foreach (@datas){
		($bitem, $bvalue) = split("\t");
		$bsel = ($bitem eq $item) ? "SELECTED" : ""; 
		$html_select_options .= "<OPTION $bsel>$bitem\n";
	}
	
	$C{'event'} = $event;
	$C{'pwd'} = $pwd;
	$C{'verno'} = $verno;
	
	if($show eq 'com'){
		$C{'comments'} = &html_allcomment;
	}
	elsif($password eq $pwd){
		$C{'form'} = &html_adminform;
	}
	else{
		$C{'form'} = &html_form;
		$C{'ranking'} = &html_ranking;
		($iltime >= 0) && ($C{'right'} = &html_right);
		($ilog) && ($C{'logs'} = &html_log);
		($icom) && ($C{'comments'} = &html_comment);
	}
	
	foreach (@tps){
		s/#CHK:(\w+)#/$C{$1}/;
		print;
	}
}



##### 投票用フォーム
sub html_form{
	local($htmlbuf, $bitem, $bvalue, $bnew, $bsel);
	
	$htmlbuf .= "
	<FORM NAME=\"FORM\" METHOD=\"$method\" ACTION=\"tvote.$ext\">
	<INPUT TYPE=\"hidden\" NAME=\"event\" VALUE=\"$event\">
	<INPUT TYPE=\"hidden\" NAME=\"sid\" VALUE=\"$new_sid\">
	<B>■ 投票用フォーム</B><BR><BR>
	○ 投票 → 
	<SELECT NAME=\"item1\" SIZE=\"1\">
	$html_select_options
	</SELECT><BR>
	";
	
	if($inew){
		$htmlbuf .= "○ 項目追加 → <INPUT TYPE=\"text\" NAME=\"item2\" SIZE=\"20\"><BR>";
	}
	
	if($icom){
		$htmlbuf .= "○ コメント → <INPUT TYPE=\"text\" NAME=\"com\" SIZE=\"50\"><BR>
		<FONT SIZE=\"2\">※ タグは使用できません。</FONT><BR>
		";
	}
	
	$htmlbuf .= "
	<BR>
	<INPUT TYPE=\"submit\" NAME=\"add\" VALUE=\"投票\">
	<INPUT TYPE=\"submit\" NAME=\"check\" VALUE=\"順位確認\">
	</FORM><HR SIZE=\"1\">
	";
	
	$htmlbuf;
}



##### 順位表
sub html_ranking{
	local($htmlbuf, $rate);
	local($bitem, $bvalue, $vall, $vitem, $i);
	
	### 総票数、ついでに順位確認
	($FORM{'check'}) && ($chk = $item);
	$i = 0;
	$vall = 0;
	foreach (@datas){
		($bitem, $bvalue) = split("\t");
		$vall += $bvalue;
		($bitem eq $chk) && ($insert_point = $i);
		$i++;
	}
	### 総項目数
	$vitem = @datas;
	### 強調表示する部分
	($insert_point) || ($insert_point = 0);
	
	### 表示範囲($from, $to)の決定
	# 投票直後（前後２件）
	if($item){
		$from = $insert_point - 2;
		$to = $insert_point + 2;
	}
	# 全件
	elsif($show eq 'all'){
		$from = 0;
		$to   = $#datas;
	}
	# 件数指定
	else{
		$show = $show || $ishow; # 表示件数のデフォルト
		$from = 0;
		$to = $show - 1;
	}
	# 調整
	($from < 0) && ($from = 0);
	($to > $#datas) && ($to = $#datas);
	# 表示範囲（順位）
	$html_scope = sprintf("%d位〜%d位", $from + 1, $to + 1);
	
	### ヘッダ
	$htmlbuf = "
	<TABLE WIDTH=\"80%\" BGCOLOR=\"#FFFFFF\" CELLPADDING=\"1\" CELLSPACING=\"1\" BORDER=\"1\">
	<CAPTION>
	▼ <B>$html_scope</B> （全$vitem項目） 【投票総数：$vall票】  ▼<BR>
	</CAPTION>
	<TR BGCOLOR=\"$nback\">
	<TD WIDTH=\"5%\" NOWRAP><FONT COLOR=\"$nfont\">順位</FONT></TH>
	<TD WIDTH=\"5%\" NOWRAP><FONT COLOR=\"$nfont\">票数</FONT></TH>
	<TD WIDTH=\"5%\" NOWRAP>　</TH>
	<TD>　</TD></TR>
	";

	### 順位付と総票数の計算（同点同順位）
	$i = -1;
	$vop = (split("\t",$datas[0]))[1] + 1;
	foreach (@datas){
		$i++;
		
		# 通常か強調か
		($font, $back, $bb, $br) = ($i != $insert_point) ? ($nfont, $nback) : ($efont, $eback, "<B>", "</B>");
		
		($bitem, $bvalue) = split("\t");
		
		# グラフ
		$rate = &calc_rate($bvalue, $vall);
		$w = int($igraph * $rate / 100) || (1);
		$rate = "<TABLE BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"0\"><TR><TD WIDTH=\"$w\" BGCOLOR=\"$font\" NOWRAP><FONT SIZE=\"1\" COLOR=\"$font\">.<FONT></TD><TD NOWRAP><FONT COLOR=\"$font\" SIZE=\"2\">... $rate%</FONT></TD></TR></TABLE>";
		
		if($vop > $bvalue){
			$ir = $i + 1; # 票数が変わったら順位を変える
			$vop = $bvalue;
		}
		
		($i < $from) && next; # from未満なら飛ばす
		($i > $to) && last; # toより大きければ終了
		
		$htmlbuf .= "
		<TR BGCOLOR=\"$back\">
		<TD NOWRAP><FONT COLOR=\"$font\">$bb$ir位$br</FONT></TD>
		<TD NOWRAP ALIGN=\"right\"><FONT COLOR=\"$font\">$bb${bvalue}票$br</FONT></TD>
		<TD NOWRAP>$rate</FONT></TD>
		<TD NOWRAP><FONT COLOR=\"$font\">$bb$bitem$br</FONT></TD></TR>
		";
		
	}
	$htmlbuf .= "</TABLE><HR SIZE=\"1\">";
	
	$htmlbuf;
}



##### 投票権
sub html_right{
	local ($htmlbuf, $html_limit, $html_date);
	
	if($iltime > 0){
		$html_date  = "<U>次回の制限リセット：<B>" . &get_time($rtime, 1);
		$html_date .= "</B></U>（現在：" . &get_time($time_sec, 1) . "）<BR><BR>";
		$html_limit = " $iltime 時間につき";
	}
	
	$htmlbuf .= "
	<B>■ 制限 <U>【 $html_limit $ilnum 票まで （１ホストあたり） 】</U></B><BR><BR>
	ホスト：<B>$user_ip</B>／残り権利数：<B>$vrlest 票</B><BR><BR>
	$html_date
	<B>＜これまでの投票内容＞</B><BR>
	";
	
	foreach (@uright){
		$htmlbuf .= (split("\t"))[1] . "／";
	}
	$htmlbuf .= "<BR><BR><HR SIZE=\"1\">\n";
	
	$htmlbuf;
}



##### ログ
sub html_log{
	"<FONT SIZE=\"2\"><B>■ 最近の投票</B><BR><UL>@logs</UL></FONT><HR SIZE=\"1\">";
}



#### コメント
sub html_comment{
	local($htmlbuf, $html_acom);
	
	($ircom) && ($html_acom = "[→ <A HREF=\"tvote.$ext?event=$event&show=com\"><B>全コメントを表\示</B></A>]");
	"<FONT SIZE=\"2\"><B>■ 最近のコメント</B> $html_acom<BR><UL>@coms</UL></FONT><HR SIZE=\"1\">";
}



##### 全コメント
sub html_allcomment{
	local(@bufs);
	
	&openfile($acomfile, *bufs);
	
	"<FONT SIZE=\"2\"><B>■ 全コメント</B> [→ <A HREF=\"tvote.$ext?event=$event\">戻る</A>]<BR><UL>@bufs</UL></FONT><HR SIZE=\"1\">";
}



### 管理用フォーム
sub html_adminform{
	local($htmlbuf);
	
	($inew) ? ($C{'inewo'} = "CHECKED") : ($C{'inewn'} = "CHECKED");
	($ircom) ? ($C{'ircomo'} = "CHECKED") : ($C{'ircomn'} = "CHECKED");
	$C{'icom'} = $icom;
	$C{'ilog'} = $ilog;
	$C{'ishow'} = $ishow;
	$C{'iltime'} = $iltime;
	$C{'ilnum'} = $ilnum;
	$C{'nback'} = $nback;
	$C{'nfont'} = $nfont;
	$C{'eback'} = $eback;
	$C{'efont'} = $efont;
	$C{'igraph'} = $igraph;
	
	$tpfrag = 1;
	foreach (@atps){
		(/^<TEMPLATE TYPE="(\w+)">/) && ($1 ne $mode) && ($tpfrag = 0); 
		(/^<\/TEMPLATE>/) && ($tpfrag = 1);
		($tpfrag) || next;
		
		s/#CHK:(\w+)#/$C{$1}/;
		s/#OPTIONS#/$html_select_options/;
		s/#MESSAGE#/$admmsg/;
		$htmlbuf .= $_;
	}
	
	$htmlbuf;
}

#################### ＨＴＭＬ表示関数　ここまで ####################


##### 日本語のデコード
sub decode{
	($org)=@_;
	$org =~ tr/+/ /;
	$org =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
	$org =~ s/\t//g;
	$org =~ s/</&LT;/g;
	$org =~ s/>/&GT;/g;
	$org =~ s/\cM//g;
	$org =~ s/\n//g;
	&jcode'convert(*org, $code);
	$org;
}



###### ファイルを開いて、中身を配列に代入する
sub openfile{
	local ($filename, *buf, $frag) = @_;
	open(FILE, "$filename") || $frag || &error(1, $filename);
	@buf = <FILE>;
	close(FILE);
	
	(@buf) ? return(1) : return(0);
}



###### ファイルを更新する
sub updatefile{
	local ($filename, *bufs, $buf, $frag) = @_;
	
	# フラグあり→追加、なし→更新
	if($frag){
		open(FILE, ">>$filename") || &error(1, $filename);
	}
	else{
		open(FILE, ">$filename") || &error(1, $filename);
	}
	print FILE @bufs;
	print FILE $buf;
	close(FILE);
}



##### 得票率の計算
sub calc_rate{
	local($a, $b) = @_;
	local ($t) = ($b) ? int($a/$b*1000) : 0;
	($t < 10) && ($t = "0$t");
	substr($t, -1, 0) = ".";
	
	$t;
}



##### 秒を時間に変える
sub get_time{
	local($stime, $format) = @_;
	local($sec, $min, $hour, $mday, $mon, $year) = localtime($stime);
	$mon = $mon + 1;
	$year += 1900;
	
	($format) || (return sprintf("%02d/%02d/%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec));
	($format == "1") && (return sprintf("%2d月%2d日 %2d時%02d分", $mon, $mday, $hour, $min));
}



##### ファイルロック
sub lock{
	$try = 0;
	while(!(symlink("$$",$lockfile))){
		(++$try > 3) && &error("", 0);
		sleep(1);
	}
}



##############################################
# symlink が使えないサーバー用のファイルロック
##############################################
#sub lock{
#	$try=0;
#	while(-f $lockfile){
#		(++$try>3) && &error(0);
#		sleep(1);
#	}
#	open(FILE,">$lockfile") ||  &error(1, $lockfile);
#	close(FILE);
#}
##############################################



##### ロック解除
sub unlock{
	unlink($lockfile);
}



##### エラーメッセージ
sub error{
	local ($id, $file) = @_;
	local (@sts) = lstat($lockfile);
	local ($tn) = time();
	
	$fmid[0] = 0; $msg[0] = 'ロック中です';
	$fmid[1] = 1; $msg[1] = 'ファイルが開けません';
	$fmid[2] = 1; $msg[2] = 'ファイルに書き込めません';
	$fmid[3] = 1; $msg[3] = 'ファイルが存在しません';
	$fmid[4] = 0; $msg[4] = 'eventが指定されていません';
	$fmid[5] = 0; $msg[5] = '管理エラー';
	$fmid[6] = 0; $msg[6] = '投票権理数オーバーです';
	$fmid[7] = 0; $msg[7] = '新項目の追加はできません';
	$fmid[8] = 0; $msg[8] = '変数が不正です';
	$fmid[9] = 0; $msg[9] = 'コメントの二重投稿が検出されました';
	
	$fmsg[0] = "ブラウザの「戻る」ボタンで戻ってください";
	$fmsg[1] = "管理者<A HREF=\"mailto:$admin_email\">$admin_email</A>に連絡してください";
	
	$fid = $fmid[$id];
	($file) && ($file = "($file)");
	
	print "<HTML><HEAD><TITLE>T-Vote - ERROR!</TITLE></HEAD><BODY BGCOLOR=\"#FFFFFF\"><FONT SIZE=\"4\"><CENTER><B>!! ERROR !!</B><P><B>$msg[$id] </B><BR>$file<P>$fmsg[$fid]<HR></FONT></BODY></HTML>";
	
	($id) && &unlock; # ID が 0 以外の場合はロック解除
	($tn - $sts[9] < 15) || &unlock; # 約15秒以上ロックが続いてたら自動解除
	exit;
}
