#!/usr/bin/perl

### PHP-READ START ###
$title = "Bubu XService";
$pidir = "/home/pi";
$sdir = "$pidir/bubu";
$tdir = "$sdir/thumbnails";
$hdir = "$pidir/smarthome";
$passfile = "$hdir/password.txt";
$libhandler = "$hdir/changeSetting.sh";
$xlogfile = "$sdir/xservice.cgi.log"; # will be flushed when bubu starts
$control = "$sdir/control.sh";
$wordtest = "$sdir/wordtester.sh";
$conv2mp3 = 0;
$remote = "$sdir/remote.sh";
$rooffile = "$sdir/playAtRoof.sh";
$factfile = "$sdir/playAtFactory.sh";
$middlefile = "$sdir/playAtMiddle.sh";
$errfile = "$sdir/xservice.err";
$tmpfile = "$sdir/xservice.tmp";
$tmpfile2 = "$sdir/xservice.tmp2";
$tmpfile3 = "$sdir/xservice.tmp.$$";
$xsrvsh = "$sdir/xservice.sh";
$xsrvcmd = "$sdir/xservice.cmd";
$htmfile = "$sdir/control.htm";
$tsfile = "$sdir/browser.ts";
$resfile = "$sdir/exe.result";
$intfile = "$sdir/interprete.result";
$lastfile = "$sdir/control.last";
$movefile = "$sdir/control.move";
$listfile = "$sdir/control.list";
$tvlist = "$sdir/tv.list";
$newslist = "$sdir/news.list";
$youtubelist = "$sdir/youtube.list";
$shfile = "$hdir/checkmail.sh";
$infile = "$hdir/inhouse.sh";
$exfile = "$hdir/execcommand.sh";
$stfile = "$hdir/getstatus.sh";
$sofile = "$hdir/searchObjectLog.sh";
$bufile = "$sdir/display.sh";
$csfile = "$sdir/editcsv.pl";
$s2tfile = "$sdir/speech2text.sh";
$defaction = "control";
$redirectDefault = 200; # in milli sec: the timeout for redirections via Javascript
$photodir = "$hdir/PHOTOS";
$sounddir = "$hdir/SOUNDS";
$audiomaxconcat = 30;
$audiomaxshuffle = 8;
$uploaddirtmp = "/var/upload";
$uploadmaxsize = 5*1024*1024*1024;
$sharedir = "$sdir/WEBSHARE";
$sharedirwww = "/WEBSHARE";
$concatdir = "/media/disc/Audio/Smarthome/Concats";
$deaffile = "$hdir/house.stateBeforeDeaf.txt";
$keedir = "$pidir/keepass";
$keehandler = "$sdir/handleKeepassHtml.pl";
$moneyhandler = "$sdir/handleMoneyManager.sh";
$moneydir = "$pidir/mmex/MoneyManagerAnalyse";
$moneyhandlerbook = "$moneydir/convertBookings.pl";
$balancefile = "$moneydir/Balances.csv"; # Bank;Date;Amount
$sqldbfile = "$sdir/bubu.sqlite3";
$credfile = "$sdir/credit.pl";
$domainextern = "sbruegmann.mooo.com"; # only for webshare links
$domainextern = "qiaowangluo.hopto.org"; # only for webshare links
### PHP-READ END ###
%dirs = (
'music', '/home/pi/Music',
'audio', '/media/disc/Audio',
'video', '/media/disc/Video',
'pictures', '/media/disc/Pictures'
);
$todayM = `date +%Y-%m-%d`; chomp($todayM);
$today = `date +%y%m%d`; chomp($today);
$now = `date +%H%M`; chomp($now);
$nowM = `date +%H:%M:%S`; chomp($nowM);
$todayY = `date +%Y`; chomp($todayY);
@allhosts = qw(smarthome factory stockage leisure garage rooftop);


use CGI;
#use CGI qw(-utf8);


if($ENV{'QUERY_STRING'}=~/mediator=getSpecialPassword/){
	$pw = `cat $passfile|base64`;
	chomp($pw);
	print CGI::header();
	print "$pw";
	exit 0;
}

#printEnvironment();


$action = "";
$openedlogfile = 1;
open(L, ">>$xlogfile") or $openedlogfile = 0;
# this page is linked from /var/cgi-bin/bubu and as such callable by https://smarthome/cgi-bin/bubu
# it needs as well a sub folder images: /var/www/images to /home/pi/bubu/images (and check all links in /var/www)
# note: in /etc/apache2/envvars, the vars APACHE_RUN_USER= and APACHE_RUN_GROUP= should set to pi
# this page is executed as AJAX request by control.htm (written by control.sh), if user clicks on any link
# but meanwhile, it servs the whole website
$q = $ENV{'QUERY_STRING'};
$referer = $ENV{'HTTP_REFERER'};
$needAuth = 1;
if($q!~/\S/){
	$q = $ARGV[0];
	$needAuth = 0;
}


#printlg("- query: $q") if($q!~/^ts=/ and $q!~/^gl=/ and $q ne "lm" and $q ne "ls" and $q ne "mv" and $q ne "er");
@pairs = split(/\&/, $q);
for($p=0;$p<$#pairs+1;$p++){
	($key, $val) = split(/=/, $pairs[$p]);
#	printli("$key: $val") if($key ne "ts" and $key ne "lm" and $key ne "ls" and $key ne "lm" and $key ne "mv" and $key ne "er" and $key ne "gl" and $q!~/interface/ and $key ne "entry" and $key ne "sheet" and $q!~/mediator/);
#	printlg("- $key: $val");
	$$key = $val;
}

if($action eq "interface" and $entry!~/\S/){
	printlg("Note: incomplete query: $q");
	exit 0;
}


# security check for external calls
$srv = $ENV{HTTP_HOST};
$nowts = time;
$maxvalid = 20;
$caller = "intern";
$caller = "extern" if($srv!~/smarthome/ and $srv!~/192.168.2.31/ and $needAuth);

$generalAllowance = 0;
$generalAllowance = 1 if(
						($mediator eq "browse" and $dir=~/\bconcats\b/i)
						or $mediator eq "concatinfo" or $mediator eq "readtextfile" or $mediator eq "getmediaduration"
						or ($interface eq "media" and $entry eq "concats")
						or ($interface eq "bible" and $entry eq "search")
						or ($interface eq "host" and $entry eq "cleaner")
						);

$queryIsAboutDjk = 0;
$queryIsAboutDjk = 1 if($q=~/entry=djk/);


$query = 0;
if($caller eq "extern" and !$generalAllowance and !$queryIsAboutDjk){
	$query = new CGI;
	$remcookie = $query->cookie("BUBU");
# "CREATE TABLE 'cookies' ('timestamp' INT unsigned,'cookie' VARCHAR(100),PRIMARY KEY ('timestamp','cookie'));"
	$loggedin = 0;
	use Data::Dumper;
	@lines = sqliteQuery("select timestamp, cookie from cookies;"); # 1st line are captions
	for($i=0;$i<$#lines+1;$i++){
		($timestamp, $cookie) = @{$lines[$i]}; # 2nd line is: ----------  ----------------------------------------------------------------------------------------------------
		if($nowts-$timestamp>$maxvalid*3600){
			sqliteQuery("delete from cookies where timestamp='$timestamp' and cookie='$cookie'");
		} elsif($cookie eq $remcookie){
			$loggedin = 1;
		}
	}
	if(!$loggedin){
		if($q!~/remote=login/){
			print CGI::header();
			printHead("Password required");
			print "<form action='/cgi-bin/bubu?remote=login' method='post'>";
			print "<input type='password' name='password'/><br/><input type='submit' value='Login'/>";
			print "<input type='hidden' name='origquery' value=\"$q\"/></form>";
			printJavascript("document.forms[0].elements[0].focus();");
			printFoot();
		}
		else{
			$rempass = $query->param('password');
			$origquery = $query->param('origquery');
			if($rempass eq "GodsOwn1"){
				@set = ('0' ..'9', 'A' .. 'Z');
				$str = join '' => map $set[rand @set], 1 .. 100;
				$cookie = $query->cookie(-name=>'BUBU',
			 		-value=>$str,
								-SameSite=>'Strict',
			 		-expires=>"+${maxvalid}h",
			 		-path=>'/');
				print $query->header(-cookie=>$cookie);
				sqliteQuery("insert into cookies ('timestamp', 'cookie') values($nowts, '$str'); commit;");
#print CGI::header();
				printHead("Success");
				print "You can now navigate without limits for $maxvalid hours. You are redirected ...";
				$redir = "/cgi-bin/bubu?$origquery";
				$redir = "/control.htm" if($origquery!~/\S/);
				printRedirect("$redir", "timeout");
				printFoot();
			}
			else{
				sleep 0;
				print CGI::header();
				printHead("Wrong password");
				print "This password is not correct!";
				printFoot();
			}
		}
	}
	else{
		printlg("- the cookie $remcookie is correct!");
	}
}
elsif($caller eq "extern" and $queryIsAboutDjk){
	if($q!~/remote=login/){
		$djkNr = 2;
		$djkNr = $1 if($q=~/=djk(\d)/);
		print CGI::header();
		printHead("Password required");
		print "<form action='/cgi-bin/bubu?remote=login&entry=djk$djkNr' method='post'>";
		print "<input type='password' name='password'/><br/><input type='submit' value='Login'/>";
		print "<input type='hidden' name='origquery' value=\"$q\"/></form>";
		printJavascript("document.forms[0].elements[0].focus();");
		printFoot();
	}
	else{
		$query = new CGI;
		$rempass = $query->param('password');
		$origquery = $query->param('origquery');
		if($rempass ne "Is4Djk" or $rempass!~/\S/){ # Ich spiele für Djk
			sleep 0;
			print CGI::header();
			printHead("Wrong password");
			print "This password is not correct!";
			printFoot();
		}
		$q = $origquery;
		@pairs = split(/\&/, $q);
		for($p=0;$p<$#pairs+1;$p++){
			($key, $val) = split(/=/, $pairs[$p]);
			$$key = $val;
		}
	}
}



#print CGI::header();
print CGI::header("text/html;charset=UTF-8");

#printlg("ENV{'QUERY_STRING'}". $ENV{'QUERY_STRING'});


# if query_string is "start", do nothing
if($q eq "start"){
#	exit 0;
}



if($interface eq "general"){ # this happens only after a successful login (for extern) or a login is not needed (intern)
	if($entry eq "reload"){
		system("$sdir/now.sh >/dev/null 2>&1");
		printRedirect("/now.htm");
		exit 0;
	}
	if($entry eq "bibledaily"){
		printHead("Select daily random scripture");
		printCommandAjax("$sdir/bible.now.sh");
		printFoot();
	}
	if($entry eq "backuplist"){
		printHead("Show last backups");
		@backups = ("smarthome.bubu");
		for($h=0;$h<$#allhosts+1;$h++){
			push(@backups, $allhosts[$h] .".smarthome");
		}
		for($b=0;$b<$#backups+1;$b++){
			($host, $dir) = split(/\./, $backups[$b]);
			printP("<pre>HOST $host\n===============");
			$param = "smarthome";
			$param = $dir if($host eq "smarthome");
			printCommandAjax("$stfile -c backup -r $host -p $param");
			printCommandAjax("$sofile -c backup -r $host -p $param -q last10");
		}
		printFoot();
	}
	if($entry eq "fixurls"){
		printHead("Upload fixed Url file");
		printFocus("general", "fixurls");
		println("- pdf2txt: $pdf2txt");
		println("- urlNr: $urlNr");
		println("- filename: $filename");
		$iserr = 0;
		$converted = 0;
		if(lc(getFileExt($filename) eq "pdf") and $pdf2txt eq "true"){
			$textname = $filename;
			$textname =~ s/pdf$/txt/i;
			$basename = getBaseName($filename);
			system("rm -f $textname") if(-f $textname);
			@lines = getCommandOutput("pdftotext -eol unix $filename $textname && rm -f $filename && cat $textname");
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$iserr = 1 if($line=~/ERROR/);
				println(toEntities($line));
			}
			if($iserr){
				println("- since there was an error, try again ...");
			}
			else{
				$filename = $textname;
				$converted = 1;
			}
		}
		if(!$iserr){
			$newfile = "$sdir/fix$urlNr.htm";
			system("mv $filename $newfile");
			printP("- file $filename has been uploaded and moved to directory $sdir");
			printRedirect("/fix$urlNr.htm", "wait");
		}
		if($converted){
			system("echo '<pre>' >$tmpfile; cat $sdir/fix$urlNr.htm >>$tmpfile; echo '</pre>' >>$tmpfile; mv $tmpfile $sdir/fix$urlNr.htm");
		}
		printFoot();
	}
	if($entry eq "backup"){
		printHead("Create backups");
		@backups = ("smarthome.bubu");
		for($h=0;$h<$#allhosts+1;$h++){
			push(@backups, $allhosts[$h] .".smarthome");
		}
		for($b=0;$b<$#backups+1;$b++){
			($host, $dir) = split(/\./, $backups[$b]);
			printP("<pre>HOST $host\n===============");
			printCommandAjax("ssh $host $pidir/$dir/backup.sh");
		}
		printFoot();
	}
	if($entry =~ /djk(\d)/){
		$nr = $1;
		$nr = 2 if($nr!~/\S/);
		open(F, "/var/cgi-bin/djk.htm") or die("ERROR: cannot read file djk.htm: $!");
		while(<F>){
			$line = $_;
			$line =~ s/%DJKNR%/$nr/g;
			print $line;
		}
		close(F);
		exit(0);
	}
	printHead("Login");
	if($caller eq "extern"){
		println("You are logged in and can now navigate without limits.<br/><br/><a href='/interface.htm?init=media,concats' target='_top'>Here</a> is the music.");
	} else{
		println("No login needed - it's only for externals");
	}
	printFoot();
}

if($interface eq "games"){
	$guy = "kai";
	$guy = "nick" if($entry=~/nick/);
	$guy = "papa" if($entry=~/papa/);
	if($entry eq "${guy}_correct"){
		printHead("Correct directory /home/$guy/www");
		println("sudo chown -R $guy:$guy /home/$guy/www");
		system("sudo chown -R $guy:$guy /home/$guy/www");
		println("sudo chmod -R 777 /home/$guy/www");
		system("sudo chmod -R 777 /home/$guy/www");
		println("Ok, rights have been corrected. You are redirected ...");
		printRedirect("/$guy", "wait");
		printFoot();
	}
	if($entry eq "papa_docu"){
		$nowts = time;
		$docdir = "$pidir/GamesLib";
		@intro = getLinesOfFile("$docdir/intro.htm");
		printHead("Re-create the GamesLib docu");
# you need to install node.js, nvm, npm and then jsdoc
		printCommandOutput("$pidir/node_modules/jsdoc/jsdoc.js -c $docdir/conf.json -d $docdir /home/papa/www/src/gameslib.js", "The documentation is created anew ...");
		system("mv $docdir/index.html $docdir/index2.html");
		@files = qw(gameslib.js.html global.html index2.html);
		for($f=0;$f<$#files+1;$f++){
			$file = "$docdir/". $files[$f];
			@lines = getLinesOfFile($file);
			for($n=0;$n<$#lines+1;$n++){
				$lines[$n] =~ s/index.html/index2.html/g;
				if($file=~/index2/){
					$lines[$n] =~ s/<h1 class=\"page-title\">Home<\/h1>//;
					$lines[$n] =~ s/<body>/<body onload='loadIntro()'>/;
					if($lines[$n]=~/<h3> <\/h3>/){
						$lines[$n] = "<div id='intro'></div><script language='javascript'>function loadIntro(){var xhr = new XMLHttpRequest(); xhr.open('GET', '/gameslib/intro.htm?$nowts'); xhr.onreadystatechange = function (){ if(xhr.readyState==4 && xhr.status==200) document.getElementById('intro').innerHTML = parent.buildLinks(xhr.responseText); }; xhr.send(null); }</script>";
					}
				}
			}
			open(F, ">$file") or die("ERROR: cannot write file $file: $!");
			print F join("\n", @lines);
			close(F);
		}
		println("Switch to <a href='/gameslib/'>GamesLib docu</a>");
		printFoot();
	}
	if($entry eq "${guy}_new"){
		printHead("Create new file");
		if($filename=~/^([\w\/]+)\.(\w{2,3})$/){
			$ext = lc($2);
			$filename = $1;
			$sub = "";
			if($filename=~/\//){
				@elems = split(/\//, $filename);
				$sub = $elems[0];
				$filename = $elems[1];
			}
			$folder = "/home/$guy/www";
			$folder .= "/$sub" if($sub ne "");
			system("mkdir -p $folder") if(! -d $folder);
			println("- create file $filename.$ext in folder $folder ...");
			if(-f "$folder/$filename.$ext"){
				println("ERROR: the file exists already!");
			} else{
				system("sudo touch $folder/$filename.$ext");
				system("sudo chmod 666 $folder/$filename.$ext");
				if(open(F, ">$folder/$filename.$ext")){
					if($ext eq "htm"){
						print F "<html>\n<head>\n\t<title>Here is the title</title>\n\t<meta charset='UTF-8'/>\n\t<script language='javascript'>nowts = new Date().getTime();
document.writeln(\"<link rel='stylesheet' href='src/styles.css?\"+ nowts +\"'/>\");
document.writeln(\"<script language='javascript' src='/gameslib.js?\"+ nowts +\"'><\\/script>\");
document.writeln(\"<script language='javascript' src='src/$filename.js?\"+ nowts +\"'><\\/script>\");
</script>";
						print F "</head>\n<body onload='init()'>\nHere is the page\n<script language='javascript'>
// preloadImage(image-path);
</script>\n</body>\n</html>\n";
					} elsif($ext eq "js"){
						print F "function init(){\n\talert('The page is loaded');\n}\n";
					} elsif($ext eq "css"){
						print F "b,p,div,span,h1,h2,h3,h4,h5,h6,li,td,body{ font-family:arial,helvetica,sans-serif; font-size:large }\n";
					}
					close(F);
					if($ext eq "htm"){
						if(open(F, ">$folder/src/$filename.js")){
							print F "function startGame(){\n
}\n
function objectReaction(object, message){\n
}\n
function openHelp(){\n
}\n";
							close(F);
						} else{
							println("NOTE: could not write file $folder/src/$filename.js!");
						}
					}
					println("Ok, file has been written. You are redirected ...");
					printRedirect("/cgi-bin/bubu?interface=games&entry=${guy}_correct", "wait");
				} else{
					println("ERROR: cannot write file $folder/$filename.$ext: $!");
				}
			}
		} else{
			println("ERROR: wrong file name ('$filename')!");
		}
		printFoot();
	}
	if($entry eq "${guy}_img"){
		printHead("Upload image");
#			$filename = uploadFile(1024 * 1024 * 50, "database", $sharedir, "%BASE%.$tstamp.kdbx");
		$imgdir = "/home/$guy/www/images";
		system("mv $filename $imgdir");
		println("	- it has been moved into directory $imgdir");
		println("- switching to correct rights ...");
		printRedirect("/cgi-bin/bubu?interface=games&entry=${guy}_correct", "wait");
		printFoot();
	}
	if($entry eq "editfile"){
		if($referer=~/games/ or $password!~/\S/ or checkSpecialPassword($password)){
			$file =~ s/\/home\/home\/www/\/home/ if($file!~/^\/media\//);
			$file = "/home/$file" if($file!~/^\/home\// and $file!~/^\/media\//);
			printHead("Edit file $file");
			if(! -f $file){
				println("ERROR: file $file does not exist or is not a file!");
			} else{
				println("<form action=\"/cgi-bin/bubu?interface=games&entry=editsave&file=$file\" method='post'><textarea name='content' rows='40' cols='200'>");
				print join("\n", getLinesOfFile($file));
				println("</textarea><br/><br/><button onclick=\"parent.loadPageWithConfirm('Sure to save?', 'form', self.document.forms[0]);\"> Save </button></form>");
			}
		} else{
			println("Not allowed");
		}
		printFoot();
	}
	if($entry eq "editsave"){
		$file = "/home/$file" if($file!~/^\/home\// and $file!~/^\/media\//);
		printHead("Save file");
		$filename = postIntoFile(1024*1024*50, "content", "$file");
				if($filename!~/^ERROR:/){
						println("- file $file has been written, switching back to edit ...");
						printRedirect("/cgi-bin/bubu?interface=games&entry=editfile&file=$file", 0);
				} else{
						println($filename);
				}
		printFoot();
	}
}

if($interface eq "media"){
	if($entry eq "check"){
		printHead("Check running players ...");
		printCommandAjax("ps -ef|egrep 'playAt[A-Z][a-z]*\.sh|playerSender\.sh|playsound\.sh'", "- checking all player processes ...");
	} elsif($entry eq "stop"){
		printHead("Stop running players ...");
		printCommandAjax("ps -ef|egrep 'playAt[A-Z][a-z]*\.sh|playerSender\.sh|playsound\.sh'|grep -v grep|awk '{print \$2}'|xargs kill -9", "- stopping all player processes ...");
		printCommandAjax("rooftop:/home/pi/smarthome/killsound.sh", "- stopping player processes on rooftop ...");
		printCommandAjax("factory:/home/pi/smarthome/killsound.sh", "- stopping player processes on factory ...");
	} else{
		printHead("Bubu Media");
		printRedirect("/media.htm?ts=$nowts&start=$entry", 0);
	}
	printFoot();
}

if($interface eq "auto"){
	if($entry eq "events"){
		printHead("Auto handler events");
		$comp = "auto";
		printSystemCommand("State", "$sofile -q state -c $comp");
		printSystemCommand("Last actions", "$sofile -q last10 -c $comp");
		printSystemCommand("Today's actions", "$sofile -q today -c $comp");
	} elsif($entry eq "objects"){
		$mode = "normal";
		$mode = "single" if($single=~/\S/);
		printHead("Auto handler objects") if($mode eq "normal");
		println("<table border='0' cellpadding='0' cellspacing='10'>") if($mode eq "normal");
		$olist = `$hdir/automodeHandler.sh list`; chomp($olist);
		@allobjects = sort(split(/\s+/, $olist));
		$afile = "$hdir/automode.txt";
		open(F, "<$afile") or die("ERROR: cannot read $afile: $!");
		while(<F>){
			chomp($_);
			push(@currobjects, $_) if($_=~/\S/);
		}
		close(F);
		for($a=0;$a<$#allobjects+1;$a++){
			$allobj = $allobjects[$a];
			$active = "disabled";
			for($c=0;$c<$#currobjects+1;$c++){
				$currobj = $currobjects[$c];
				$active = "enabled" if($currobj eq $allobj);
			}
			$color = "blue"; # active
			$color = "orange" if($active eq "disabled"); # not active
			$tcolor = "white"; # active
			$tcolor = "black" if($active eq "disabled"); # not active
			$flag = "manual"; # flag for change
			$flag = "auto" if($active eq "disabled");
			$text = "disable"; # text for change
			$text = "enable&nbsp;" if($active eq "disabled");
			println("<tr><td>$allobj</td><td style='background-color:$color;color:$tcolor'>&nbsp;&nbsp;$active&nbsp;&nbsp;</td><td><button onclick=\"parent.loadPageWithConfirm('Are you sure to $text $allobj?', '/cgi-bin/bubu?interface=auto&entry=change&obj=$allobj&setting=$flag');\">&nbsp;$text&nbsp;</button></td></tr>") if($mode eq "normal" or $allobj eq $single);
		}
		println("</table>") if($mode eq "normal");
	} elsif($entry eq "change"){
		printHead("Change auto handler object");
		printCommandOutput("$hdir/automodeSetter.sh $obj $setting", "- changing $obj to $setting ...");
		printRedirect("/cgi-bin/bubu?interface=auto&entry=objects", "wait");
	} elsif($entry=~/^cron_(.+)$/){
		$host = $1;
		printHead("Crontab of $host");
		system("ssh $host 'crontab -l' >$sdir/cron.$host.txt");
		@lines = getLinesOfFile("$sdir/cron.$host.txt");
#		system("rm -f $sdir/cron.$host.txt");
		$ok = 0;
		$ok = 1; # because automatic installation of the comments section doesn't work
		println("Format: m h  dom mon dow   command");
		println("==================================");
		println("<form action='/cgi-bin/bubu?interface=auto&entry=cronsave_$host' method='post'><textarea rows='30' cols='140' name='crontab'>");
		for($n=0;$n<$#lines+1;$n++){
			$line = $lines[$n];
			if($line=~/m\s+h\s+dom\s+mon\s+dow\s+command/){
				$ok = 1;
				next;
			}
			next if(!$ok);
			println($line);
		}
		println("</textarea><br/><br/><button onclick=\"parent.loadPageWithPassword('form', self.document.forms[0]);\">Save crontab</button></form>");
	} elsif($entry=~/^cronsave_(.+)$/){
		$host = $1;
		printHead("Save crontab of $host");
		if(checkSpecialPassword($password)){
			$filename = postIntoFile(1024*1024*1, "crontab", "$hdir/cron.$host.txt");
					if($filename!~/^ERROR:/){
							println("- file $filename has been posted, applying to $host ...");
				system("scp $hdir/cron.$host.txt $host:$hdir") if($host ne "smarthome");
				system("ssh $host 'ls -al $hdir/cron.$host.txt' 2>/dev/null >$hdir/cron.$host.tmp");
				@lines = getLinesOfFile("$hdir/cron.$host.tmp");
				$line = $lines[0];
				if($line=~/^\-[rwx\-]{9}\s+\d+\s+pi\s+pi\s+(\d+)\s+\S.+\s+\d+\s+\d+:\d+\s+(\S.+)$/){
					$size = $1;
					$name = $2;
					if($size>0 and $name eq "$hdir/cron.$host.txt"){
						println("- the upload of the crontab worked, going to apply it ...");
						system("ssh $host 'crontab <$hdir/cron.$host.txt'");
						printRedirect("/cgi-bin/bubu?interface=auto&entry=cron_$host", "wait");
					} else{
						println("ERROR: the upload to $host somehow didn't work!");
					}
				} else{
					println("ERROR: the check if the file has been uploaded to $host, looks like:\n$line");
				}
					} else{
							println($filename);
					}
		} else{
			println("Not allowed");
		}
	}
	printFoot() if($mode eq "normal");
}

if($interface eq "alarm"){
	if($entry eq "show"){
		printHead("Show alarm events");
		printFocus("alarm", "show");
		$res = getCommand("$hdir/getstatus.sh -c alarm");
		$nr = $1 if($res=~/\s(\d+)$/);
		$flag = "active";
		$flag = "blocked" if("$nr" eq "0");
		println("<h3>Blockage:</h3>");
		println("<pre>");
		println("- current state of alarm: $flag");
		println("</pre>");
		$comp = "alarm";
		printSystemCommand("Last actions", "$sofile -q last10 -c $comp");
		printSystemCommand("Today's actions", "$sofile -q today -c $comp");
	} elsif($entry eq "settings"){
		printHead("Settings of automated alarm");
		printFocus("alarm", "settings");
		println("<form method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$filter = "alarm";
		@lines = getCommandOutput("$libhandler -a list -f $filter");
		for($n=0;$n<$#lines+1;$n++){
			$line = $lines[$n];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name', 'rooftop');\" onfocus='this.select()' size='40'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name', 'smarthome');\">&nbsp;Save&nbsp;</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name, host){ formobj = document.forms[0]; if(host=='rooftop') formobj = document.forms[1]; val=formobj.elements[name].value; formobj.action=\"/cgi-bin/bubu?interface=alarm&entry=change&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=$filter&host=\"+ host +\"\"; parent.loadPageWithPassword('form', formobj); }</script>");
		println("<form method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$filter = "btnLeft,btnSound";
		@lines = getCommandOutput("$libhandler -a list -f $filter -r rooftop");
		for($n=0;$n<$#lines+1;$n++){
			$line = $lines[$n];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name', 'rooftop');\" onfocus='this.select()' size='40'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name', 'rooftop');\">&nbsp;Save&nbsp;</button></td></tr>");
		}
		println("</table></form>");
	}
	elsif($entry eq "change"){
		printHead("Change an alarm setting");
		printFocus("alarm", "settings");
		if(checkSpecialPassword($password)){
			$value = urldecode($value);
			$iserr = printCommandOutput("$libhandler -a change -s $setting -p \"$value\" -r $host");
			printP("OK! Setting '$setting' has been changed to \"$value\" on host $host") if(!$iserr);
		}
		printRedirect("/cgi-bin/bubu?interface=alarm&entry=settings&filter=$filter&password=$password", "wait");
	}
	elsif($entry eq "test"){
		printHead("Test the alarm sound");
		printFocus("alarm", "test");
		$iserr = printCommandOutput("rooftop:$hdir/alarm.sh -t");
		println($iserr ? "There was an error" : "The current alarm sound has been tested");
	}
	elsif($entry eq "stop"){
		printHead("Stop the alarm sound");
		printFocus("alarm", "stop");
		$iserr = printCommandOutput("rooftop:$hdir/killsound.sh");
		println($iserr ? "There was an error" : "The current alarm sound has been stopped");
	}
	elsif($entry eq "switch_on" or $entry eq "switch_off"){
		$flag = "on";
		$flag = "off" if($entry=~/_off/);
		$act = 1;
		$act = 0 if($flag eq "off");
		printHead("Switch alarm $flag");
		printFocus("alarm", "$entry");
		$iserr = printCommandOutput("$hdir/execcommand.sh -c alarm:$act -q");
		println($iserr ? "There was an error" : "The alarm has been switched $flag");
	}
	printFoot();
}

if($interface eq "pump"){
	if($entry eq "list"){
		printHead("Pump");
		$comp = "pumpe_schacht";
		printCommandAjax("$sofile -q state -c $comp", "State");
		printCommandAjax("$sofile -q last10 -c $comp", "Last actions");
		printCommandAjax("$sofile -q today -c $comp", "Today's actions");
		printFoot();
	}
	if($entry eq "pump_stop"){
		printSystemCommand("Pump stop", "$exfile -c pumpe_schacht:0");
		printAction("pump", "pump_new");
		printFoot();
	}
	if($entry eq "showmode"){
		printSystemCommand("Show pump mode", "factory:cat $hdir/pumpmode.txt");
		printFoot();
	}
	if($entry eq "togglemode"){
		$res = `ssh factory "cat $hdir/pumpmode.txt"`; chomp($res);
		$newstate = ($res eq "manual" ? "webbased" : "manual");
		printSystemCommand("Toggle pump mode", "factory:echo $newstate >$hdir/pumpmode.txt");
		println("- the pump mode has been switched from $res to $newstate (host factory, file $hdir/pumpmode.txt)");
		printFoot();
	}
	if($entry eq "pump_run"){
		printHead("Pump run");
		if(checkSpecialPassword($password)){
			printCommandOutput("$exfile -c pumpe_schacht:$seconds", "run for $seconds seconds");
			printAction("pump", "pump_new");
		}
		printFoot();
	}
	if($entry=~/_new/){
		@files = dirFilterPos("Slurry", readDirectory($photodir));
		$lastphoto = $files[-1];
		printSystemCommand("Create slurry photo", "$exfile -c foto_schacht:1");
		@files = dirFilterPos("jpg", dirFilterPos("Slurry", readDirectory($photodir)));
		$currphoto = $files[-1];
		printP("- last photo: $lastphoto");
		println("- current photo: $currphoto");
		if($currphoto eq $lastphoto){
			println("ERROR: that somehow didn't work!");
		} else{
			$photo = "/PHOTOS/". $currphoto;
			println("OK - load the newest photo ...");
			printRedirect("$photo", "wait");
		}
		printFoot();
	}
	@files = dirFilterPos("jpg", dirFilterPos("Slurry", readDirectory($photodir)));
	$photo = "/PHOTOS/". $files[-1];
	printRedirect($photo);
	println("... loading $photo ...");
	printFoot();
}

if($interface eq "photo"){
	$orgentry = $entry;
	if($entry=~/new_/){
		$entry =~ s/new_//;
		$Entry = uc(substr($entry, 0, 1)). substr($entry, 1);
		$entry = ($entry eq "stock" ? "vorrat" : "schacht");
		@files = dirFilterPos("jpg", dirFilterPos($Entry, readDirectory($photodir)));
		$lastphoto = $files[-1];
		printHead("Create $Entry photo");
		println("- last photo: $lastphoto");
		printCommandOutput("$exfile -c foto_$entry:1", "- create new $Entry photo ...");
		@files = dirFilterPos("jpg", dirFilterPos($Entry, readDirectory($photodir)));
		$currphoto = getBaseName($files[-1]);
		println("\n- current photo: $currphoto");
		if($currphoto eq $lastphoto){
			println("ERROR: that somehow didn't work!");
		} else{
			$photo = "/PHOTOS/". $currphoto;
			println("OK - load the newest photo ...");
			printRedirect("$photo", "wait"); # printRedirect
		}
		printFoot();
	}
	$entry = $1 if($entry=~/list_(\S+)/);
	$Entry = uc(substr($entry, 0, 1)). substr($entry, 1);
	$Entry = "Stock" if($entry eq "stock_forward");
	$photodir = "$hdir/PHOTOS";
	@files = dirFilterPos("jpg", dirFilterPos($Entry, readDirectory($photodir)));
	$photo = "/PHOTOS/". getBaseName($files[-1]);
	if($orgentry=~/list_/){
		$Entry = uc(substr($entry, 0, 1)). substr($entry, 1);
		printHead("List $Entry photos");
		$top = 240;
		$left = 440;
		println("<script language='javascript'>function deletePhoto(photo){ if(confirm('Are you sure to delete '+ photo +'?')==true){ self.location.href='/cgi-bin/bubu?interface=photo&entry=${entry}_delete&delphoto='+ photo; }}</script>");
		println("<script language='javascript'>function showImage(img){with(document.getElementById('playerContainer')){ style.visibility='visible'; style.display='block'; style.opacity=''; style.position= '-webkit-sticky; sticky'; style.top='${top}px'; style.left='${left}px'; innerHTML=\"<img id='mediaplayer' style='display:inline; position: -webkit-sticky, sticky; top:${top}px; left:${left}px;' src='\"+ img +\"'/>\"; }}</script>");
		println("<script language='javascript'>function hideImage(){with(document.getElementById('playerContainer')){ style.display='none'; }}</script>");
		println("<table border='0' cellpadding='3' cellspacing='5'>");
		@files = reverse(@files);
		for($f=0;$f<$#files+1;$f++){
			$base = getBaseName($files[$f]);
			$file = "/PHOTOS/$base";
			println("<tr><td onmousemove=\"showImage('$file');\" onmouseout=\"hideImage();\">$file</td><td><button onclick=\"deletePhoto('$base')\">Delete</button></td></tr>");
		}
		println("</table><div id='playerContainer' style='display:none;visibility:hidden'></div><div id='stage' style='display:none;visibility:hidden'></div>");
	}
	elsif($entry=~/^(.+)_delete/){
		$entry = $1;
		$Entry = uc(substr($entry, 0, 1)). substr($entry, 1);
		printHead("Delete $Entry photo");
		$photo = "$photodir/". urldecode($delphoto);
		unlink($photo);
		println("- deleted $photo");
		printRedirect("/cgi-bin/bubu?interface=photo&entry=list_$entry");
	}
	elsif($entry eq "stock_forward"){
		printHead("Forward latest stock photo");
		printCommandOutput("$hdir/sendmail.sh -r xbruegmann\@gmail.com -s \"Smarthome: latest stock photo\" -b \"This is the latest stock photo\" -a $photodir/". $files[-1], "- forward latest stock photo $photo to xbruegmann\@gmail.com ...");
	} elsif($entry=~/_settings/){
		$Entry = "S". $1 if($entry=~/^s(\w+)_settings/);
		$entry = lc($Entry);
		printHead("Settings of $Entry");
		printFocus("photo", $entry);
		println("<form method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$filter = "$entry";
		@lines = getCommandOutput("$libhandler -a list -f $filter -r factory");
		for($n=0;$n<$#lines+1;$n++){
			$line = $lines[$n];
			println($line) if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='40'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">&nbsp;Save&nbsp;</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.value; formobj.action=\"/cgi-bin/bubu?interface=photo&entry=${entry}_change&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=$filter\"; parent.loadPageWithPassword('form', formobj); }</script>");
	} elsif($entry=~/_change/){
		$Entry = "S". $1 if($entry=~/^s(\w+)_change/);
		$entry = lc($Entry);
		$filter = $entry;
		printHead("Change a $entry photo setting");
		printFocus("photo", "${entry}_settings");
			if(checkSpecialPassword($password)){
				$value = urldecode($value);
				$iserr = printCommandOutput("$libhandler -a change -s $setting -p \"$value\" -r factory");
				printP("OK! Setting '$setting' has been changed to \"$value\"") if(!$iserr);
				printRedirect("/cgi-bin/bubu?interface=photo&entry=${entry}_settings&filter=$filter&password=$password", "wait");
			}
	} else{
		printRedirect($photo);
		#println($photo);
		println("... loading $photo ...");
	}
	printFoot();
}

if($interface eq "light"){
	if($entry eq "state"){
		printHead("Status of all lights");
		@lights = qw(stock slurry schach sofa schrank musik extern ecke eingang);
		foreach $light(@lights){
			printCommandAjax("$stfile -c licht_$light", "cap:Light $light");
		}
	} elsif($entry eq "settings"){
		printHead("Settings of automated lights");
		printFocus("light", "settings");
		println("<form method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$filter = "light";
		@lines = getCommandOutput("$libhandler -a list -f $filter");
		for($n=0;$n<$#lines+1;$n++){
			$line = $lines[$n];
			println($line) if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='40'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">&nbsp;Save&nbsp;</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; formobj.action=\"/cgi-bin/bubu?interface=light&entry=change&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=$filter\"; parent.loadPageWithPassword('form', formobj); }</script>");
	}
	elsif($entry eq "change"){
		printHead("Change a light setting");
		printFocus("light", "settings");
		if(checkSpecialPassword($password)){
			$value = urldecode($value);
			$iserr = printCommandOutput("$libhandler -a change -s $setting -p \"$value\"");
			printP("OK! Setting '$setting' has been changed to \"$value\"") if(!$iserr);
			$filter = "light";
			printRedirect("/cgi-bin/bubu?interface=light&entry=settings&filter=$filter&password=$password", "wait");
		}
	}
	else{
		$flag = "on";
		$flag = "off" if($entry=~/_off/);
		$act = 1;
		$act = 0 if($flag eq "off");
		$kind = "summary";
		$kind = "switch" if($entry=~/_on|_off/);
		$entry =~ s/_on|_off//;
		$orgentry = $entry;
		$entry = "schach" if($entry eq "chess");
		$entry = "schrank" if($entry eq "cupboard");
		$entry = "musik" if($entry eq "music");
		$entry = "ecke" if($entry eq "corner");
		$entry = "eingang" if($entry eq "entry");
		$comp = "licht_$entry";
		if($kind eq "switch"){
			printHead("Light $light");
			println("$exfile -c licht_$entry:$act");
			printSystemCommand("Change light $orgentry", "$exfile -c licht_$entry:$act");
		} else{
			printHead("Summary of light $entry", "yes", "no");
			printCommandAjax("$sofile -q state -c $comp", "cap:State");
			printCommandOutput("$sofile -q last50 -c $comp", "cap:Last actions");
			printCommandOutput("$sofile -q today -c $comp", "cap:Today's actions");
		}
	}
	printFoot();
}

if($interface eq "sauna"){
	if($entry eq "settings"){
		printHead("Sauna sensor settings");
		printFocus("sauna", "settings");
		println("<form method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$filter = "sauna";
		@lines = getCommandOutput("$libhandler -a list -f $filter -r factory");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='40'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">&nbsp;Save&nbsp;</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; formobj.action=\"/cgi-bin/bubu?interface=sauna&entry=settingchange&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=$filter\"; parent.loadPageWithPassword('form', formobj); }</script>");
	}
	elsif($entry eq "settingchange"){
		printHead("Change a sauna sensor setting");
		printFocus("sauna", "change");
		if(checkSpecialPassword($password)){
			$value = urldecode($value);
			$filter = "sauna";
			@lines = getCommandOutput("$libhandler -a change -s $setting -p \"$value\" -r factory");
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$iserr = 1 if($line=~/ERROR/);
				println($line);
			}
			println("OK! Setting '$setting' has been changed to \"$value\"") if(!$iserr);
			printRedirect("/cgi-bin/bubu?interface=sauna&entry=settings&filter=$filter&password=$password", "wait");
		}
	}
	elsif($entry eq "music"){
		printHead("Select music directory");
		$mfile = "$sdir/control.htm";
		$currdir = `grep -i browse: $mfile 2>/dev/null`; chomp($currdir);
		$currdir = $1 if($currdir=~/browse:\s+(\S.+)$/i);
		$currdir =~ s/\/+$//;
		$defdir = getLibrarySetting("saunaMusicDef");
		$libdir = getLibrarySetting("saunaMusic");
		println("<pre>");
		println("- setting: $libdir");
		println("- current selection: $currdir");
		println("- default: $defdir");
		println("<script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; formobj.action=\"/cgi-bin/bubu?interface=sauna&entry=change&dir=\"+ formobj.dir.value; parent.loadPageWithConfirm('Sure to save (since all files will be uploaded, it will take some time)?', 'form', formobj); }</script>");
		println("<form onsubmit='return false;'><table border='0' cellpadding='0' cellspacing='5'><tr><td><input type='text' name='dir' value='$libdir' size='60' onfocus='this.select()' /></td>");
		println("<td><button onclick=\"document.forms[0].dir.value=top.currentMediaPlayerFile;\">&nbsp;Current&nbsp;</button></td>");
		println("<td><button onclick=\"document.forms[0].dir.value='$defdir';\">&nbsp;Default&nbsp;</button></td>");
		println("<td><button onclick=\"saveSetting();\">&nbsp;Save&nbsp;</button></td>");
		println("</tr></table></form>");
	}
	if($entry eq "change"){
		printHead("Change music directory");
		$dir =~ s/\/\/+/\//g;
		println("- check, if given directory '$dir' has sub directories ...");
		$exists = 1;
		$exists = 0 if(!-d "$dir");
		$hassub = 0;
		$hassub = 1 if(grep -d, glob("$dir/*"));
		if(!$exists){
			println("ERROR: given directory '$dir' does not exist!");
			printRedirect("/cgi-bin/bubu?interface=sauna&entry=music", "wait");
		} elsif($hassub){
			println("ERROR: given directory '$dir' has a sub directory!");
			printRedirect("/cgi-bin/bubu?interface=sauna&entry=music", "wait");
		} else{
			println("	- ok, no sub directories!");
			$iserr = printCommandOutput("$libhandler -a change -s saunaMusic -p \"$dir\"");
			if($iserr){
				printP("There was an error!");
				printRedirect("/cgi-bin/bubu?interface=sauna&entry=music", "wait");
			} else{
				println("OK! Sauna music directory has been changed to \"$dir\"\n<pre>");
				@files = readDirectory($dir);
				for($f=0;$f<$#files+1;$f++){
					$file = $files[$f];
					$ok = 1;
					$locsize = getFileSize("$dir/$file");
					$remsize = getFileSize("factory:$hdir/SOUNDS/$file");
					$ok = 0 if("$remsize" eq "$locsize");
					if($ok){
						@lines = getCommandOutput("scp \"$dir/$file\" pi\@factory:$hdir/SOUNDS", "- upload $file to factory ...");
						for($n=0;$n<$#lines+1;$n++){
							$line = $lines[$n];
							$iserr = $line if($line=~/ERROR/i or $line=~/FATAL/i or $line=~/could not resolve/i or $line=~/no such file/i or $line=~/no such directory/i or $line=~/no such path/i);
						}
						if($iserr){
							println("ERROR: $iserr");
						} else{
							println("	- ok!");
						}
					} else{
						println("- file $file ...");
						println("	- no upload needed, file size is the same at factory ($locsize)!");
					}
				}
			}
		}
	}
	if($entry eq "play"){
		printHead("Play sauna music");
		$entry = getLibrarySetting("saunaMusic");
		if(-f $entry){
			println("- going to play at factory file '$entry' ...");
			$iserr = printWgetOutput("/cgi-bin/bubu?mediator=send2player&player=factory&files=$entry");
		}
		elsif(-d $entry){
			println("- going to play at factory all files of '$entry' ...");
			$iserr = printWgetOutput("/cgi-bin/bubu?mediator=send2player&player=factory&dir=$entry");
		}
		else{
			println("ERROR: entry '$entry' does not exist (resp. is neither directory nor file)!");
		}
	}
	if($entry eq "stop"){
		printHead("Stop sauna music");
		println("- going to stop at factory the current music ...");
		printWgetOutput("/cgi-bin/bubu?action=control&entry=stop");
	}
	if($entry eq "runs"){
		printHead("List sauna runs");
		$cost5min = `$hdir/changeSetting.sh -a list -r factory -f saunacost5min 2>/dev/null|grep ^saunacost5min|awk '{print \$3}'`; chomp($cost5min);
		$costpower = `$hdir/changeSetting.sh -a list -f powerAvgHourPrice 2>/dev/null|grep ^powerAvgHourPrice|awk '{print \$3}'`; chomp($costpower);
		system("ssh factory 'cat /home/pi/smarthome/saunaruns.csv'|sed -e 's%^%<tr><td>%' -e 's%;%  </td><td>  %g' -e 's%\$%</td></tr>%' 2>&1 >$tmpfile2");
		println("<table border='0' cellpadding='9' cellspacing='9'>");
		open(F, "<$tmpfile2") or die("ERROR: cannot read $tmpfile2: $!");
		while(<F>){
			chomp($_);
			$line = $_;
			if($line=~/(\d\d:\d\d).+(o[fn]f?)/){
				$tstamp = $1;
				$switch = $2;
				$offtime = $tstamp if($switch eq "off");
				$ontime = $tstamp if($switch eq "on");
			}
			if($switch eq "off"){
				println($line);
				$lastline = "off";
			} elsif($switch eq "on"){
				$offsec = time2sec($offtime);
				$onsec = time2sec($ontime);
				$dur = int(($offsec - $onsec)/60);
				$units = int($dur/5);
				$price = round2dec($units * $cost5min * $costpower);
				if($lastline eq "on"){
					splice(@prices, -1);
					splice(@durs, -1);
				}
				push(@prices, $price);
				push(@durs, $dur);
				$line =~ s/(<\/td><\/tr>)/ &nbsp; $dur, $price $1/;
				println($line);
				$lastline = "on";
			} else{
				$line =~ s/(<\/td><\/tr>)/ &nbsp; Duration, EUR $1/;
				println($line);
			}
		}
		close(F);
		for($p=0;$p<$#prices+1;$p++){
			$total += $prices[$p];
			$durtot += $durs[$p];
		}
		println("<tr><td colspan='3' align='right'>Total $durtot min, $total EUR</td></tr>");
		println("</table>");
	}
	printFoot();
}

#printlg("- interface: $interface, entry: $entry");

if($interface eq "webshare"){
	if($entry eq "delete"){
		printHead("Delete webshare file");
		println("- delete $sharedir/$file ...");
		$res = getCommand("rm -f $sharedir/$file");
		println("	". ($res=~/\S/ ? "ERROR!" : "OK"));
		printRedirect("/cgi-bin/bubu?interface=webshare&entry=list");
	}
	elsif($entry eq "list"){
		printHead("List webshare files");
		printFocus("webshare", "list");
		$sorter = "N" if($sorter!~/\S/);
		$recursive = substr($sorter, 1);
		$recursive = 1 if($recursive eq "r");
		$recursive = 0 if("$recursive" ne "1");
		println("<script language='javascript'>var rec=$recursive; if(rec==1) rec=''; else rec='r'; function sort(mode){ document.location.href='/cgi-bin/bubu?interface=webshare&entry=list&sorter='+mode+rec; } var wins=new Array(); var winid=0; function openInWin(url){ wins.push(window.open(url, 'popup'+ winid, 'fullscreen')); winid++; if (wins[wins.length-1].outerWidth < screen.availWidth || wins[wins.length-1].outerHeight < screen.availHeight){ wins[wins.length-1].moveTo(0,0); wins[wins.length-1].resizeTo(screen.availWidth, screen.availHeight); }}</script>");
		println("<table cellpadding='0' cellspacing='10' border='0'>");
		println("<tr><th><a href=\"javascript:sort('N');\">File</a></th><th><a href=\"javascript:sort('S');\">Size</a></th><th><a href=\"javascript:sort('D');\">Date</th><td colspan='4'>&nbsp;</a></td></tr>");
		$s = "";
		$s = "t" if($sorter=~/D/);
		$s = "S" if($sorter=~/S/);
		$s .= "r" if($recursive);
		@wfiles = getCommandOutput("ls -l$s $sharedir");
		# -rw-r--r--  1 pi   pi	  59044 May  4  2020 test.wav
		for($f=0;$f<$#wfiles+1;$f++){
			my($r, $x, $u, $g, $s, $d1, $d2, $d3, $wfile) = split(/\s+/, $wfiles[$f]);
			next if($r!~/^\-/ and $r!~/^l/);
			println("<tr><td>$wfile</td><td>$s</td><td>$d1 $d2 $d3</td><td><button onclick=\"document.location.href='/cgi-bin/bubu?interface=webshare&entry=download&file=$wfile';\">&nbsp;Download&nbsp;</button></td><td><button onclick=\"openInWin('/cgi-bin/bubu?interface=webshare&entry=download&file=$wfile');\">&nbsp;Open&nbsp;</button></td><td><button onclick=\"parent.loadPageWithConfirm('Sure to delete?', '/cgi-bin/bubu?interface=webshare&entry=delete&file=$wfile');\">&nbsp;Delete&nbsp;</button></td><td><input type='text' size='3' value=\"https://$domainextern$sharedirwww/$wfile\" onfocus='this.select()'></td></tr>");
		}
		println("</table>");
	}
	elsif($entry eq "download"){
		printHead("Download webshare files");
		printFocus("webshare", "download");
		if($file!~/\S/){
			println("ERROR: no file given!");
		} else{
			$fullfile = "$sharedirwww/$file";
			println("- download <a id='dlink' href=\"$fullfile\">$fullfile</a> ..");
			printRedirect("$fullfile");
		}
	}
	elsif($entry eq "multiple"){ # because of AJAX, print only the uploaded file name
		println(uploadFile(1024 * 1024 * 1024 * 10, "uploadfile", $sharedir));
	}
	elsif($entry eq "upload"){
#printEnvironment();
		printHead("Upload webshare file");
		printFocus("webshare", "upload");
		println("- pdf2txt: $pdf2txt");
#		$filename = uploadFile(1024 * 1024 * 1024 * 10, "uploadfile", $sharedir, "uploaded");
		system("mv $filename $sharedir");
		$filename  = $sharedir ."/". getBaseName($filename);
		if($filename!~/^ERROR:/){
			printP("- file $filename has been uploaded and moved to directory $sharedir");
			if(lc(getFileExt($filename) eq "pdf") and $pdf2txt eq "true"){
				$textname = $filename;
				$textname =~ s/pdf$/txt/i;
				system("rm -f $textname") if(-f $textname);
				$iserr = 0;
				@lines = getCommandOutput("pdftotext -eol unix $sharedir/$filename $sharedir/$textname && rm -f $sharedir/$filename && cat $sharedir/$textname");
				for($l=0;$l<$#lines+1;$l++){
					$line = $lines[$l];
					$iserr = 1 if($line=~/ERROR/);
					println(toEntities($line));
				}
				if($iserr){
					println("- since there was an error, we redirect ...");
#					printRedirect("/cgi-bin/bubu?interface=webshare&entry=list", "wait");
				}
			} else{
#				printRedirect("/cgi-bin/bubu?interface=webshare&entry=list", "wait");
			}
		} else{
 			println($filename);
		}
	}
	printFoot();
}

if($interface eq "house"){
	if($entry eq "creditScript"){
		printHead("Credit script");
		printCommandOutput("cat $credfile");
		printFoot();
	}
	$Entry = uc(substr($entry, 0, 1)) . substr($entry, 1);
	printHead("$Entry") if($entry!~/^credit/i and $entry!~/notes/ and $entry!~/insurance/);
	printFocus("house", $entry);
	$dir = "/media/disc/Storages/$Entry" if($dir!~/\S/);
	println("- current directory: $dir<br/><br/>") if($entry!~/^credit/i and $entry!~/notes/ and $entry!~/insurance/);
	if($entry eq "notes" or $entry eq "insurance"){
		printHead("<h2>Edit $entry</h2>");
		println("<script language='javascript'>parent.focusType('house'); parent.focusSub('house', '$entry');</script>");
		println("<form action='/cgi-bin/bubu?interface=house&entry=${entry}save' method='post'><textarea rows='30' cols='140' name='$entry'>");
		@lines = getLinesOfFile("$sdir/$entry.txt");
		println(join("\n", @lines));
		println("</textarea><br/><br/><button onclick=\"parent.loadPageWithConfirm('Sure to save?', 'form', self.document.forms[0]);\"> Save </button></form>");
		printFoot();
	}
	elsif($entry eq "notessave" or $entry eq "insurancesave"){
		$entry =~ s/save//;
		printHead("Save $entry");
		if(1 or checkSpecialPassword($password)){
			$filename = postIntoFile(1024*1024*5, "$entry", "$sdir/$entry.txt");
			   		if($filename!~/^ERROR:/){
					   		println("- file $filename has been posted, switching to edit ...");
					   		printRedirect("/cgi-bin/bubu?interface=house&entry=$entry&password=$password", "wait");
			   		} else{
					   		println($filename);
			   		}
		} else{
			println("Not allowed.");
		}
		printFoot();
	} elsif($action=~/\S/ and checkSpecialPassword($password)){
		if($action eq "upload"){
#			$filename = uploadFile(1024 * 1024 * 1024 * 10, "uploadfile", $dir);
			system("mv $filename $dir");
			$filename  = $dir ."/". getBaseName($filename);
			if($filename!~/^ERROR:/){
				printP("- file $filename has been uploaded and moved to directory $dir<br/><br/>");
			} else{
 				println($filename);
			}
		} elsif($action eq "mkdir"){
			println("- create directory $dir/$newdir ...<br/><br/>");
			system("mkdir $dir/$newdir");
		} elsif($action eq "delete"){
			println("- delete entry $dir/$file ...<br/><br/>");
			if(-f "$dir/$file"){
				system("rm -f $dir/$file");
			} elsif(-d "$dir/$file"){
				system("rmdir $dir/$file");
			}
		}
	}
	elsif($entry=~/^credit/i){
		$entry =~ s/^credit//i;
		$entry = lc($entry);
		$Entry = uc(substr($entry, 0, 1)). substr($entry, 1);
		printHead("Credit $Entry");
		$todate = `date +%Y/%m`; chomp($todate);
		$iserr = 0;
		@lines = getCommandOutput("perl $credfile $entry");
		$countrest = 0;
		$monthrest = 0;
		$debtrest = 0;
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			$iserr = 1 if($line=~/ERROR/);
			if($line=~/$todate/){
				$line = "<b>". $line ."</b>";
				$countrest = 1;
			}
			$monthrest++ if($countrest);
			println($line);
			$debtrest = $1 if($line=~/=\s*(\d+\.?\d*)\s*$/);
		}
		println("- still $monthrest months to go (set aside each month: ~". round2dec($debtrest / $monthrest) .")");
		if($iserr){
			println("There was an error");
		} else{
			$debttotal = 0;
			$debt = 0; $creditsum = 0;
			println("&nbsp;");
			@lines = getCommandOutput("perl $credfile house");
			for($l=0;$l<$#lines+1;$l++){
				$creditsum = $1 if($lines[$l]=~/credit sum:\s+([\d\.]+)\b/);
				if($lines[$l]=~/$todate:.+=\s+([\d\.]+)\b/){
					$debt = $1;
					last;
				}
			}
			$debt = $creditsum if(!$debt);
			$laolaoPlus = 45000;
			$jiejiePlus = 75000;
			$laolaoAll = $laolaoPlus;
			$jiejieAll = $jiejiePlus;
			println("- debt for the house:");
			println("  Bank: $debt EUR");
			println("  Laolao: $laolaoPlus EUR");
			println("  Jiejie: $jiejiePlus EUR");
			$debttotal += $debt;
			$debt = 0; $creditsum = 0;
			println("&nbsp;");
			@lines = getCommandOutput("perl $credfile botnang");
			for($l=0;$l<$#lines+1;$l++){
				$creditsum = $1 if($lines[$l]=~/credit sum:\s+([\d\.]+)\b/);
				if($lines[$l]=~/$todate:.+=\s+([\d\.]+)\b/){
					$debt = $1;
					last;
				}
			}
			$debt = $creditsum if(!$debt);
			$laolaoPlus = 80000;
			$jiejiePlus = 20000;
			$laolaoAll += $laolaoPlus;
			$jiejieAll += $jiejiePlus;
			println("- debt for Botnang:");
			println("  Bank: $debt EUR");
			println("  Laolao: $laolaoPlus EUR");
			println("  Jiejie: $jiejiePlus EUR");
			$debttotal += $debt;
			$debt = 0; $creditsum = 0;
			println("&nbsp;");
			@lines = getCommandOutput("perl $credfile aldingen");
			for($l=0;$l<$#lines+1;$l++){
				$creditsum = $1 if($lines[$l]=~/credit sum:\s+([\d\.]+)\b/);
				if($lines[$l]=~/$todate:.+=\s+([\d\.]+)\b/){
					$debt = $1;
					last;
				}
			}
			$debt = $creditsum if(!$debt);
			println("- debt for Aldingen:");
			println("  Bank: $debt EUR");
			$debttotal += $debt;
			println("&nbsp;");
			println("- total bank debt: $debttotal");
			println("- total laolao debt: $laolaoAll");
			println("- total jiejie debt: $jiejieAll");
			println("- total family debt: ". ($jiejieAll + $laolaoAll));
			println("- total all debt: ". ($jiejieAll + $laolaoAll + $debttotal));
			println("Done.");
		}
		printFoot();
	}
	$sorter = "N" if($sorter!~/\S/);
	$recursive = substr($sorter, 1);
	$recursive = 1 if($recursive eq "r");
	$recursive = 0 if("$recursive" ne "1");
	$s = "";
	$s = "t" if($sorter=~/D/);
	$s = "S" if($sorter=~/S/);
	$s .= "r" if($recursive);
	println("<script language='javascript'>var rec=$recursive; if(rec==1) rec=''; else rec='r'; function sort(mode){ document.location.href='/cgi-bin/bubu?interface=house&entry=$entry&dir=$dir&sorter='+mode+rec; }</script>");
	system("ls -l$s $dir >$tmpfile");
	open(F, "<$tmpfile") or die("ERROR: cannot read file $tmpfile: $!");
	$updir = getDirName($dir);
	$code .= "<script language='javascript'>";
#	$code .= "function upload(){ formobj=document.forms[0]; formobj.action += '&action=upload'; parent.loadPageWithPassword('form', formobj); }";
	$code .= "function upload(){ var pw=''; var inp=prompt('Password?'); if(inp==false || inp==null ||inp==void(0)) return; pw=inp; df=document.forms[0]; df.action = df.action.replace(/.cgi.bin.bubu/, '/upload.php'); df.action += '&action=upload&password='+ pw; df.submit(); }";
	$code .= "function editfile(dfile){ parent.loadPageWithPassword('/cgi-bin/bubu?interface=games&entry=editfile&file='+dfile); }";
	$code .= "function delfile(dfile){ formobj=document.forms[0]; formobj.action += '&action=delete&file='+ dfile; parent.loadPageWithPassword('form', formobj); }";
	$code .= "function mkdir(){ formobj=document.forms[0]; var val=formobj.newdir.value; val=val.replace(/\\s+/g, ''); if(val==''){ formobj.newdir.focus(); return; } var url='/cgi-bin/bubu?interface=house&entry=$entry&dir=$dir&action=mkdir&newdir='+ val; parent.loadPageWithPassword(url); }";
	$code .= "<\/script>";
	$code .= "<form action='/cgi-bin/bubu?interface=house&entry=$entry&dir=$dir' method='post' enctype='multipart/form-data' onsubmit=\"return false;\">";
	$code .= "<a href='/cgi-bin/bubu?interface=house&entry=$entry&dir=/media/disc/Storages/$Entry'>START</a>";
	$code .= "&nbsp;&nbsp;&nbsp;&nbsp;";
	$code .= "<a href='/cgi-bin/bubu?interface=house&entry=$entry&dir=$updir'>UP</a>";
	$code .= "&nbsp;&nbsp;&nbsp;&nbsp;";
#	$code .= "<input type='file' name='uploadfile' onchange=\"\" /><button onclick=\"upload()\">Upload</button>";
	$code .= "<input type='file' name='uploadfile' id='uploadfile' onchange=\"\" /><button onclick=\"upload()\">Upload</button>";
	$code .= "&nbsp;&nbsp;&nbsp;&nbsp;";
	$code .= "&nbsp;&nbsp;&nbsp;&nbsp;";
	$code .= "<input type='text' name='newdir' onfocus='this.select()' />";
	$code .= "<button onclick=\"mkdir()\">New directory</button>";
	$code .= "<script language='javascript'>function showImage(ifile){ if(!ifile.match(/\.jpe?g\$/i) && !ifile.match(/\.png\$/i)) return; idiv=document.getElementById('imgDisplay'); idiv.innerHTML = \"<img src='\"+ifile+\"' border='0' width='600' />\"; }<\/script>";
	$code .= "<table border='0'><tr><td valign='top'>";
	$code .= "<table border='0' cellspacing='10' cellpadding='10'><tr><th>Rights</th><th><a href=\"javascript:sort('S');\">Size</a></th><th><a href=\"javascript:sort('D');\">Date</a></th><th><a href=\"javascript:sort('N');\">Name</a></th><th></th></tr>";
	println($code);
	@lines = ();
	while(<F>){
		chomp($_);
		$line = $_;
		next if($line=~/^total/);
		($rights, $uid, $uname, $group, $bytes, $date1, $date2, $date3, $fname) = split(/\s+/, $line);
		next if($fname eq "." or $fname eq "..");
		$isdir = 0;
		$isdir = 1 if($rights=~/^d/);
		$ext = "";
		$ext = lc(getFileExt($fname)) if(!$isdir);
		if($isdir){
			$rights = "<b>D</b>". substr($rights, 1);
			$fnametag = "<a href='/cgi-bin/bubu?interface=house&entry=$entry&dir=$dir/$fname'>$fname</a>";
		} else{
			$fnametag = "<a href=\"javascript:location.href='$dir/$fname'\" onmousemove=\"showImage('$dir/$fname');\">$fname</a>";
		}
		$line = "<tr><td>$rights</td><td>$bytes</td><td>$date1 $date2 $date3</td><td>$fnametag</td><td>";
		$line .= "<button onclick=\"delfile('$fname');\">&nbsp;x&nbsp;</button>";
		$line .= "&nbsp;&nbsp;&nbsp;<button onclick=\"editfile('$dir/$fname');\">&nbsp;edit&nbsp;</button>" if($ext eq "txt" or $ext eq "js" or $ext eq "css" or $ext eq "pl" or $ext eq "htm" or $ext eq "html");
		$line .= "</td></tr>";
		$isdir ? println($line) : push(@lines, $line);
	}
	close(F);
	println(join("\n", @lines));
	println("</table></td><td valign='top' align='center'><div id='imgDisplay'></div></td></tr></table></form>");
	printFoot();
}

if($interface eq "weather"){
	$shdir = `grep "^ *shdir=" $hdir/library.sh`; chomp($shdir);
	$shdir = $1 if($shdir=~/=\s*\"(.+)?\"/);
	if($entry eq "list"){
		printHead("List weather files");
		printFocus("weather", "list");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		@files = readDirectory($shdir);
		for($f=0;$f<$#files+1;$f++){
			push(@wfiles, $files[$f]) if($files[$f]=~/weather\..*\.csv/);
		}
		for($f=0;$f<$#wfiles+1;$f++){
			$wfile = $wfiles[$f];
			println("<tr><td>$wfile</td><td><button onclick=\"document.location.href='/cgi-bin/bubu?interface=weather&entry=show&file=$wfile';\">Show</button></td></tr>");
		}
		println("</table>");
	}
	elsif($entry eq "show"){
		printHead("Show weather file");
		printFocus("weather", "show");
		$file = "weather.current.csv" if($file!~/\S/);
		$file = "$shdir/$file";
		println("- given file: $file, will be displayed in reverse order");
		if(! -f $file){
			println("ERROR: the file does not exist!");
		} else{
			$info = `ls -al $file`; chomp($info);
			println("$info");
			println("<table cellpadding='0' cellspacing='5' border='0'>");
			open(F, "<$file") or die("ERROR: cannot read file $file: $!");
			while(<F>){
				chomp($_);
				$line = $_;
				push(@wlines, $line);
			}
			close(F);
			$caption = $wlines[0];
			@wlines = reverse(@wlines);
			unshift(@wlines, $caption);
			for($w=0;$w<$#wlines+1;$w++){
				$line = $wlines[$w];
				$lnr = $w;
				if($lnr!=0){
					println("<tr><td>");
				} else{
					println("<tr><td><b>");
				}
				@fields = split(/\s*;\s*/, $line);
				if($lnr!=0){
					println(join("</td><td>", @fields));
				} else{
					println(join("</b></td><td><b>", @fields));
				}
				if($lnr!=0){
					println("</td></tr>");
				} else{
					println("</b></td></tr>");
				}
			}
			println("</table>");
		}
	}
	elsif($entry eq "forecast"){
		printHead("Show forecast file");
		printFocus("weather", "forecast");
		$file = "weather.forecast.csv" if($file!~/\S/);
		$file = "$shdir/$file";
		println("- given file: $file, will be displayed in reverse order");
		if(! -f $file){
			println("ERROR: the file does not exist!");
		} else{
			$info = `ls -al $file`; chomp($info);
			println("$info");
			println("<table cellpadding='3' cellspacing='5' border='0'>");
			open(F, "<$file") or die("ERROR: cannot read file $file: $!");
			while(<F>){
				chomp($_);
				$line = $_;
				push(@wlines, $line);
			}
			close(F);
			$caption = $wlines[0];
			@wlines = reverse(@wlines);
			unshift(@wlines, $caption);
			$lastfcdate = "";
			$lastfctsday = "";
			$lnr = 0; $imgid = 0;
			for($w=0;$w<$#wlines+1;$w++){
				$line = $wlines[$w];
				@fields = split(/\s*;\s*/, $line); # Date Time Type WeatherTS Label Temp Wind Humid Press 
				# prepare all columns
				splice(@fields, 5, 0, "Image");
				push(@fields, "Rain"); # Date Time Type WeatherTS Label Image Temp Wind Humid Press Rain
				$temp = $fields[6];
				$col = "#9c2fae";
				$col = "#663fb4" if($temp>-18);
				$col = "#4055b2" if($temp>-12);
				$col = "#587cf7" if($temp>-6);
				$col = "#1daaf2" if($temp>-1);
				$col = "#20bcd2" if($temp>4);
				$col = "#159588" if($temp>10);
				$col = "#2d9a2d" if($temp>16);
				$col = "#8cc051" if($temp>21);
				$col = "#febf2d" if($temp>27);
				$col = "#fd9728" if($temp>32);
				$col = "#fb582f" if($temp>38);
				$fields[6] = "<span style='background-color:$col;padding:3px'>". $fields[6] ."</span>" if($lnr!=0);
				$fields[7] = "0". $fields[7] if($fields[7]!~/^\d/);
				$lab = $fields[4];
				$rain = "no";
				$rain = "<b>YES</b>" if($lab=~/rain/i or $lab=~/snow/i);
				$img = $lab;
				$img =~ s/\s+//g;
				$img = "/images/$img.jpg";
				$img =~ s/light//gi if(! -f "$sdir$img");
				$fields[5] = "<img id='img$imgid' onmouseover='zoomImage($imgid)' onmouseout='callHideImage()' src='$img' height='30' alt='$lab' title='$lab' border='0'/>" if($lnr!=0);
				$imgid++;
				$fields[-1] = $rain if($lnr!=0);
				# only show the latest forecast lines
				$fcdate = $fields[0] ." ". $fields[1];
				#next if($lastfcdate!="" and $fcdate ne $lastfcdate);
				$lastfcdate = $fcdate;
				if($lnr!=0){
					println("<tr><td>"); # for at the end all lines will be reversed
				} else{
					println("<tr><td><b>");
				}
				$fcts = $fields[3];
				($fctsday, $fctstime) = split(/\s+/, $fcts);
				$fctstime =~ s/:00$//;
				if($lnr!=0){
					if($lastfctsday ne $fctsday){
						$fields[3] = "<b>$fctsday</b> $fctstime";
					} else{
						$fields[3] = "$fctsday $fctstime";
					}
				}
				$lastfctsday = $fctsday;
				if($lnr!=0){
					println(join("</td><td>", @fields));
				} else{
					for($b=0;$b<$#fields+1;$b++){ $fields[$b] =~ s/^\d+//; }
					println(join("</b></td><td><b>", @fields));
				}
				if($lnr!=0){
					println("</td></tr>");
				} else{
					println("</b></td></tr>");
				}
				$lnr++;
			}
			println("</table><div id='zoom' style='display:none'></div><script language='javascript'>var tid; function zoomImage(imgid){ if(tid) window.clearTimeout(tid); hideImage(); imgel = document.getElementById('img'+ imgid); src = imgel.getAttribute('src'); img = new Image(); img.src = src; iw = img.width; ih = img.height; fw = 300;	factor = iw / fw; fh = Math.round(ih / factor);	sw = screen.availWidth;	sh = screen.availHeight; il = Math.floor(sw/2 - fw/2)-100; it = Math.floor(sh/2 - fh/2); my=mouseY(); mx=mouseX(); if(my>=it && my<=it+fh && mx>=il && mx<=il+fw){ it=my+20; il=mx+20; } with(document.getElementById('zoom')){ style.display = 'block'; style.position = 'absolute'; style.top = it +'px'; style.left = il +'px'; innerHTML = \"<img src='\"+ src +\"' width='\"+ fw +\"' border='0'/>\"; } if(whichClient()=='mobile') tid = window.setTimeout('hideImage()', 2000); } function callHideImage(){ if(whichClient()!='mobile') hideImage(); } function hideImage(){ document.getElementById('zoom').style.display='none'; } function mouseX(evt) {if (!evt) evt = window.event; if (evt.pageX) return evt.pageX; else if (evt.clientX)return evt.clientX + (document.documentElement.scrollLeft ?  document.documentElement.scrollLeft : document.body.scrollLeft); else return 0;} function mouseY(evt) {if (!evt) evt = window.event; if (evt.pageY) return evt.pageY; else if (evt.clientY)return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop); else return 0;}</script>");
		}
	} elsif($entry eq "reports"){
		$reportdir = getLibrarySetting("reportdir");
		$reportdir =~ s/\$shdir/$hdir/g;
		printHead("Weather reports");
		@files = dirFilterPos("htm", readDirectory($reportdir));
		for($f=0;$f<$#files+1;$f++){
			$wfile = $files[$f];
			$wbase = getBaseName($wfile);
			print "<li><a href='/REPORTS/$wbase' target='_blank'>$wbase</a></li>";
		}
	} elsif($entry eq "settings"){
		printHead("Weather report settings");
		printFocus("weather", "settings");
		println("<form method='post' enctype='multipart/form-data' onsubmit='return false;'>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$filter = "report";
		@lines = getCommandOutput("$libhandler -a list -f $filter");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='40'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">&nbsp;Save&nbsp;</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; formobj.action=\"/cgi-bin/bubu?interface=weather&entry=change&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=$filter\"; parent.loadPageWithPassword('form', formobj); }</script>");
	} elsif($entry eq "change"){
		printHead("Change a weather report setting");
		if(checkSpecialPassword($password)){
			$value = urldecode($value);
			$filter = "report";
			@lines = getCommandOutput("$libhandler -a change -s $setting -p \"$value\"");
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$iserr = 1 if($line=~/ERROR/);
				println($line);
			}
			println("OK! Setting '$setting' has been changed to \"$value\"") if(!$iserr);
			printRedirect("/cgi-bin/bubu?interface=weather&entry=settings&filter=$filter&password=$password", "wait");
		}
	}
	printFoot();
}

if($interface eq "host"){
	if($entry eq "cleaner"){
		system("ssh rooftop \"/home/pi/smarthome/cleaner.sh 2>&1\" >$tmpfile 2>&1");
		open(F, "<$tmpfile") or die("ERROR: cannot read $tmpfile: $!");
		while(<F>){
			chomp($_);
			println($_) if($_=~/\S/);
		}
		close(F);
		exit;
	}
	elsif($entry=~/restart_(.+)$/){
		$host = $1;
		printHead("Restart host $host");
		if(checkSpecialPassword($password)){
			printCommandOutput("$host:sudo shutdown -r now");
		} else{
			println("Not allowed");
		}
	}
	elsif($entry=~/pins/){
		$h = $1 if($entry=~/pins_(\w+)$/);
		printHead("Pin setup of $h");
		if($h eq "rooftop"){
			println("<img src='/images/pins.rooftop1.jpg' alt='Pin setup 1 of rooftop' title='Pin setup 1 of rooftop' width='800'/>");
			println("<img src='/images/pins.rooftop2.jpg' alt='Pin setup 2 of rooftop' title='Pin setup 2 of rooftop' width='800'/>");
		}
		printFoot();
	}
	elsif($entry=~/mount/){
		$h = $1 if($entry=~/mount_(\w+)$/);
		printHead("Mount disc on $h");
		$dir = "smarthome";
		$dir = "bubu" if($h eq "smarthome");
		printCommandAjax("$h:/home/pi/$dir/mounter.sh");
		printFoot();
	}
	elsif($entry=~/command/){
		$h = $1 if($entry=~/command_(\w+)$/);
		printHead("Issue a command on $h");
		if(checkSpecialPassword($password)){
			$command = urldecode($command);
			if($command=~/\bsudo\b/ or $command=~/\bsu\b/ or $command=~/\brm\s+\*/ or $command=~/\brm\s+\-f\s+\*/){
				println("ERROR: the command is not allowed: $command");
			} else{
				printCommandAjax("$h:". $command);
			}
		} else{
			println("Not allowed");
		}
		printFoot();
	} else{
		printHead("Availability of host $entry");
		println("<style type='text/css'>div { padding:20px; width: 1000px; height: 1000px; display: block; position: relative; } div::after { content: ''; background: url(/images/host.$entry.jpg); background-size:contain; background-repeat:no-repeat; opacity: 0.5; top: 0; left: 0; bottom: 0; right: 0; position: absolute; z-index: -1; }</style><div>");
		println("<h3>Ping</h3>");
		printCommandAjax("ping -c 3 $entry");
		println("<h3>Pi Version via ssh</h3>");
		printCommandAjax("$entry:cat /sys/firmware/devicetree/base/model");
		println("<h3>Raspbian Version via ssh</h3>");
		printCommandAjax("$entry:cat /etc/os-release|grep NAME");
		println("<h3>RAM amount in kB via ssh</h3>");
		printCommandAjax("$entry:grep MemTotal /proc/meminfo");
		println("<h3>Free space of main via ssh</h3>");
		printCommandAjax("$entry:df -h /");
		println("<h3>Uptime via ssh</h3>");
		printCommandAjax("$entry:uptime");
		println("<h3>Today's reboots</h3>");
		$todayM = `date +%y%m%d`; chomp($todayM);
		$dir = "smarthome";
		$dir = "bubu" if($entry eq "smarthome");
		printCommandAjax("$entry:grep 'reboot system' $pidir/$dir/logs/reboot.$todayM.log");
		println("<h3>CPU temperature via ssh</h3>");
		printCommandAjax("$entry:echo `cat /sys/class/thermal/thermal_zone0/temp`/1000|bc");
		println("<h3>GPU temperature via ssh</h3>");
		printCommandAjax("$entry:vcgencmd measure_temp");
		println("</div>");
	}
	printFoot();
}

if($interface eq "sensor"){
	@bfiles = qw(smarthome.bubu.cam.aisle.block smarthome.bubu.cam.entry.block smarthome.bubu.cam.front.block smarthome.bubu.cam.winter.block factory.smarthome.movesensExtern.block factory.smarthome.stockdoor.block garage.smarthome.movesensEntry.block garage.smarthome.bathwin.block garage.smarthome.toiletwin.block);
	$errornr = 0;
	if($entry eq "deafstate"){
		printHead("Show house deafness");
		if(-f $deaffile){
			println("Deafness is active!");
			printP("	The current content of the deafness file:");
			open(F, "<$deaffile") or die("ERROR: cannot read file $deaffile: $!");
			while(<F>){
				chomp($_);
				$line = $_;
				println($line);
			}
			close(F);
		} else{
			println("Deafness is not active! All sensors function as their settings tell");
		}
		printFoot();
	}
	if($entry eq "deaf"){
		printHead("Make sensors and cameras deaf");
		if(checkSpecialPassword($password)){
			println("- make the house sensonrs deaf ...<pre>");
			if(-f $deaffile){
				println("HINT: I don't write the current states into $deaffile, for it exists already!");
				printP("	The current content of the file:");
				open(F, "<$deaffile") or die("ERROR: cannot read file $deaffile: $!");
				while(<F>){
					chomp($_);
					$line = $_;
					println($line);
				}
				close(F);
			} else{
				println("	- getting and writing the current states into $deaffile ...");
				open(F, ">$deaffile") or die("ERROR: cannot write file $deaffile: $!");
				for($b=0;$b<$#bfiles+1;$b++){
					$bfile = $bfiles[$b];
					if($bfile=~/^([^\.]+)\.([^\.]+)\.([^\:]+)$/){
						$host = $1;
						$dir = "$pidir/$2";
						$file = $3;
						$cont = $4;
						$res = `timeout 30 ssh $host "cat $dir/$file 2>/dev/null"`;
						$rc = $?;
						if($rc){
							println("ERROR: could not get the state of file $dir/$file, host $host!");
						} else{
							chomp($res);
							$res = "active" if($res!~/block/);
							println("		- current state of file $dir/$file, host $host is: $res");
							print F "$bfile: $res\n";
							$res = `timeout 30 ssh $host "echo block >$dir/$file"`;
							$rc = $?;
							if($rc){
								println("ERROR: could not set the block state into file $dir/$file, host $host!");
								$errornr++;
							} else{
								println("		- set 'block' into file $dir/$file, host $host");
							}
						}
					}
				}
				close(F);
				println("- all sensors have been set to 'block'") if(!$errornr);
				println("- there have been $errornr errors") if($errornr);
			}
		}
		printFoot();
	}
	if($entry eq "restore"){
		printHead("Restore sensors to previous state");
		if(checkSpecialPassword($password)){
			println("- restore house sensonrs and cameras to the previous state ...<pre>");
			if(! -f $deaffile){
				println("HINT: the file $deaffile doesn't exist, so I cannot restore (probably it's already done?)");
				printP("	- the current states are:");
				for($b=0;$b<$#bfiles+1;$b++){
					$bfile = $bfiles[$b];
					if($bfile=~/^([^\.]+)\.([^\.]+)\.([^\:]+)$/){
						$host = $1;
						$dir = "$pidir/$2";
						$file = $3;
						$cont = $4;
						$res = `timeout 30 ssh $host "cat $dir/$file 2>/dev/null"`;
						$rc = $?;
						if($rc){
							println("ERROR: could not get the state of file $dir/$file, host $host!");
							$errornr++;
						} else{
							chomp($res);
							println("		- $host:$dir/$file: $res");
						}
					}
				}
				println("- there have been $errornr errors in getting the current state") if($errornr);
			} else{
				println("	- getting the previous states from $deaffile ...");
				open(F, "<$deaffile") or die("ERROR: cannot read file $deaffile: $!");
				while(<F>){
					chomp($_);
					$line = $_;
					if($line=~/^([^\.]+)\.([^\.]+)\.([^\:]+):(.*)$/){
						$host = $1;
						$dir = "$pidir/$2";
						$file = $3;
						$cont = $4;
						$cont =~ s/\s//g;
						$cont = "active" if($cont!~/block/);
						println("	- setting file $dir/$file on $host to: $cont ...");
						$res = `timeout 30 ssh $host "echo '$cont' >$dir/$file"`;
						$rc = $?;
						if($rc){
							println("ERROR: could not set the previous state ('$cont') into file $dir/$file, host $host!");
							$errornr++;
						} else{
							chomp($res);
							println("		- OK");
						}
					}
				}
				close(F);
				unlink($deaffile);
				println("- the previous state has been restored") if(!$errornr);
				println("- there have been $errornr errors in restoring") if($errornr);
			}
		}
		printFoot();
	}
	$flag = "on";
	$flag = "off" if($entry=~/_off/);
	$orgentry = $entry;
	$entry =~ s/_o[fn]f?$//;
	$entry =~ s/sens/sensor_/ if($entry!~/sensor_/);
	$entry =~ s/ext/extern/ if($entry!~/extern/);
	$entry =~ s/ent/entry/ if($entry!~/entry/);
	$entry =~ s/fen/fenster_/ if($entry!~/fenster_/);
	$host = "factory";
	$host = "garage" if($entry=~/fenster_/ or $entry=~/ent/);
	$bfile = "movesensExtern.block";
	$bfile = "movesensEntry.block" if($entry=~/entry/);
	$bfile = "stockdoor.block" if($entry eq "sensor_stock");
	$bfile = "bathwin.block" if($entry eq "fenster_bad");
	$bfile = "toiletwin.block" if($entry eq "fenster_klo");
	$bfile = "$hdir/$bfile";
	$sfile = $bfile;
	$sfile =~ s/\.block/.schedule/;
	if($orgentry=~/_on/ or $orgentry=~/_off/){
		$cont = "";
		$cont = "block" if($flag eq "off");
		printHead("Switch sensor $entry $flag");
		println("- host $host, file $bfile, cont: $cont");
		`timeout 15 ssh $host "echo '$cont' >$bfile;" 2>&1`;
		$rc = $?;
		println("- return code: $rc");
		printRedirect("/cgi-bin/bubu?interface=sensor&entry=$entry", "wait");
	} elsif($orgentry=~/_simulate/){
		$place = "entry";
		$place = "extern" if($entry=~/extern/);
		$lfile = $bfile;
		$lfile =~ s/\.block/.last/;
		printHead("Simulate movement at $place");
		printCommandOutput("$host:sudo echo '$todayM $nowM' >$lfile");
		printSystemCommand("Content of $host:$lfile:", "$host:cat $lfile");
	} elsif($orgentry=~/_schedule$/){
		$place = "entry";
		$place = "extern" if($entry=~/extern/);
		printHead("Edit working hours of sensor $place");
		$f = $sfile;
		$w = "schedule";
		$host = "garage";
		$host = "factory" if($place eq "extern");
		if(checkSpecialPassword($password)){
			system("scp $host:$f $f");
			println("<form action='/cgi-bin/bubu?interface=sensor&entry=${orgentry}save&password=$password' method='post'><textarea rows='30' cols='180' name='$w'>");
			@lines = getLinesOfFile($f);
			println(join("\n", @lines));
			println("</textarea><br/><br/><button onclick=\"parent.loadPageWithConfirm('Sure to save?', 'form', self.document.forms[0]);\"> Save </button><br/><br/></form>");
		} else{
			println("Not allowed.");
		}
	} elsif($orgentry=~/_schedulesave$/){
		$place = "entry";
		$place = "extern" if($entry=~/extern/);
		$host = "garage";
		$host = "factory" if($place eq "extern");
		printHead("Save working hours of sensor $place");
		$f = $sfile;
		$w = "schedule";
		$e = $orgentry;
		$e =~ s/save$//;
		if(checkSpecialPassword($password)){
			$filename = postIntoFile(1024*1024*5, "$w", "$f");
			if($filename!~/^ERROR:/){
				println("- file $filename has been posted, switching to $w ...");
				printRedirect("/cgi-bin/bubu?interface=sensor&entry=$e&password=$password", "wait");
				system("scp $f $host:$f");
				system("ssh $host \"ps -ef|grep movesensE|grep -v grep|awk '{print \$2}'|xargs sudo kill -9\"");
			} else{
				println($filename);
			}
		} else{
			println("Not allowed.");
		}
	} else{
		$comp = $entry;
		$entry =~ s/^sensor_//;
		printHead("Summary of sensor $entry");
		if($entry eq "sauna"){
			printSystemCommand("Last temperature", "$sofile -q last1 -c $comp");
		} else{
			printSystemCommand("Blockage state", "timeout 15 ssh $host \"cat $bfile;\"|xargs echo _");
			println("- block file: $bfile");
		}
		printSystemCommand("State", "$sofile -q state -c $comp");
#		printSystemCommand("Last actions", "$sofile -q last10 -c $comp");
#		printSystemCommand("Today's actions", "$sofile -q today -c $comp");
	}
	printFoot();
}

if($interface eq "password"){
	if(checkSpecialPassword($password)){
		if($entry eq "list"){
			printHead("List uploaded databases");
			printFocus("password", "list");
			println("<form onsubmit='return false;'>");
			println("<table cellpadding='5' cellspacing='5' border='0'>");
			println("<tr><th>File</th><th>Size</th><th colspan='3' align='left'>Date</th></tr>");
			@lines = getCommandOutput("ls -lt $sharedir/*.kdb*");
			println("<tr><td colspan='5'>No database file found!</td></tr>") if($#lines<0);
			for($n=0;$n<$#lines+1;$n++){
				my($r, $x, $u, $g, $s, $d1, $d2, $d3, $file) = split(/\s+/, $lines[$n]);
				next if($r!~/^\-/ and $r!~/^l/);
				$file = getBaseName($file);
				println("<tr><td>$file</td>");
				println("<td>$s</td><td>$d1 $d2 $d3</td>");
				println("<td><button onclick=\"document.location.href='$sharedirwww/$file'\">Download</button></td>");
				println("<td><button onclick=\"parent.loadPageWithConfirm('Sure to delete?', '/cgi-bin/bubu?interface=password&entry=delete&database=$file&password=$password')\">Delete</button></td></tr>");
			}
			println("</table></form></pre>");
		}
		elsif($entry eq "delete"){
			printHead("Delete uploaded database");
			println("- going to delete $database ...");
			unlink("$sharedir/$database");
			println("- OK!");
			println("- switching to list ...");
			printRedirect("/cgi-bin/bubu?interface=password&entry=list&password=$password", "wait");
		}
		elsif($entry eq "upload"){
			printHead("Upload database");
			$tstamp = `date +%Y%m%d_%H%M`; chomp($tstamp);
#			$filename = uploadFile(1024 * 1024 * 50, "database", $sharedir, "%BASE%.$tstamp.kdbx");
			$stem = getStemName($filename);
			system("mv $filename $sharedir/$stem.$tstamp.kdbx");
			$filename  = "$sharedir/$stem.$tstamp.kdbx";
			if($filename!~/^ERROR:/){
				println("- file $filename has been uploaded and moved to directory $sharedir");
				printRedirect("/cgi-bin/bubu?interface=password&entry=list&password=$password", "wait");
			} else{
				println($filename);
			}
		}
		elsif($entry eq "uploadhtml"){
			printHead("Keepass HTML file upload");
			$tstamp = `date +%Y%m%d_%H%M`; chomp($tstamp);
			$filename = uploadFile(1024 * 1024 * 50, "database", $keedir, "%BASE%.$tstamp.htm");
			if($filename!~/^ERROR:/){
				println("- file $filename has been uploaded and moved to directory $keedir");
				printRedirect("/cgi-bin/bubu?interface=password&entry=list&password=$password", "wait");
			} else{
				println($filename);
			}
		}
		elsif($entry eq "search"){
			$phrase = urldecode($phrase);
			printHead("Search passwords");
			println("<pre>- get the newest HTML file ...");
			@files = dirFilterPos("htm", readDirectory($keedir));
			for($f=0;$f<$#files+1;$f++){
				push(@newfiles, $files[$f]) if($files[$f]=~/\.html?$/);
			}
			@newfiles = sort(@newfiles);
			$htmfile = "$keedir/". $newfiles[-1];
			system("$keehandler $htmfile $phrase");
		}
	}
	else{
		printHead("Not allowed");
		println("The given password ($password) is not correct!");
	}
	printFoot();
}

if($interface eq "money"){
	if($entry eq "last60"){
		printHead("Overview of all accounts for the last 60 months");
		if(checkSpecialPassword($password)){
			println("- overview of all accounts ...");
			printCommandAjax("$moneyhandler balance all last60", "- the last 60 months:");
		} else{
			println("Not allowed");
		}
	}
	if($entry eq "report"){
		printHead("Report of MoneyManager");
		if(checkSpecialPassword($password)){
			@bdkeys = ("simon", "wei", "dkb", "1822", "all");
			foreach $bdkey(@bdkeys){
				printCommandOutput("$moneyhandler balance $bdkey", "- bank $bdkey ...");
			}
			printCommandOutput("$moneyhandler balance all last12", "- the last 12 months:");
		} else{
			println("Not allowed");
		}
	}
	elsif($entry eq "csvgroc" or $entry eq "csvcar"){
		$interface = "energy";
		$entry = "carrepair" if($entry eq "csvcar");
		$entry = "food" if($entry eq "csvgroc");
		$skipEnd = 1;
	}
	elsif($entry eq "repgroc" or $entry eq "repcar"){
		$months = 12 if($months!~/\S/);
		$cat = "Food;Groceries";
		$word = "groceries";
		$cat = "Automobile;%" if($entry eq "repcar");
		$word = "the car" if($entry eq "repcar");
		printHead("Report of MoneyManager for $word of the last 12 months");
		$todY = `date +%Y`; chomp($todY); $todYOrg = $todY;
		$todM = `date +%m`; chomp($todM); $todMOrg = $todM;
		$todD = `date +%d`; chomp($todD);
		$enddate = "$todY-$todM-$todD";
		$total = 0;
		for($n=1;$n<=$months;$n++){
			$todD = 28 if($todD>28);
			$todM = $todMOrg-$n;
			if($todM<1){
				$todM += 12;
				$todY = $todYOrg - 1;
			}
			$todM = "0$todM" if($todM<10);
			$startdate = "$todY-$todM-$todD";
			@lines = getCommandOutput("$moneyhandler expenses \"$cat\" $startdate $enddate", "- $startdate till $enddate");
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$amount = $1 if($line=~/\D([\d\.]+)\s*$/);
				println($line);
					}
			$total += $amount;
			println("	- expenses: $amount");
			$enddate = $startdate;
		}
		$avg = sprintf("%.2f", $total/12);
		println("- average: $avg");
	}
	elsif($entry eq "upload"){
		printHead("Upload sheet");
		$filename = uploadFile(1024*1024*5, "sheet");
				if($filename!~/^ERROR:/){
						println("- file $filename has been uploaded, converting it to unix style ...");
			printSystemCommand("dos2unix $uploaddirtmp/$filename");
						printRedirect("/cgi-bin/bubu?interface=money&entry=test&sheet=$uploaddirtmp/$filename", "wait");
				} else{
						println($filename);
				}
	}
	elsif($entry eq "delete"){
		printHead("Delete uploaded sheet");
		println("<pre>- going to delete $sheet ...");
		unlink($sheet);
		println("- OK!");
		println("- switching to list ...");
		printRedirect("/cgi-bin/bubu?interface=money&entry=list", "wait");
	}
	elsif($entry eq "list"){
		printHead("List uploaded sheets");
		printFocus("money", "list");
		println("<pre><table cellpadding='0' cellspacing='5' border='0'>");
		@lines = getCommandOutput("find /var/upload -type f -iname \"*.csv\" -printf \"%T@ %Tc %p\n\"|sort -n");
		$nr = 0;
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			$line =~ s/^.+(\/var\/.*)$/$1/;
			$nr++;
			println("<tr><td>$line</td><td><button onclick=\"document.location.href='/cgi-bin/bubu?interface=money&entry=test&sheet=$line';\">&nbsp;Test&nbsp;</button>&nbsp;&nbsp;&nbsp;<button onclick=\"parent.loadPageWithConfirm('Sure to remove it?', '/cgi-bin/bubu?interface=money&entry=delete&sheet=$line');\">&nbsp;Delete&nbsp;</button></button>&nbsp;&nbsp;&nbsp;<button onclick=\"document.location.href='/cgi-bin/bubu?interface=money&entry=display&sheet=$line';\">&nbsp;Display&nbsp;</button></td></tr>");
		}
		println("<tr><td colspan='2'>No database file found!</td></tr>") if(!$nr);
		println("</table>");
	}
	elsif($entry eq "test" or $entry eq "display"){
			$filename = $sheet;
		$filename = getFirstLineOfFile($tmpfile2) if($sheet eq "last");
		$word = "Test"; $word = "Display" if($entry eq "display");
		printHead("$word uploaded sheet");
		if($filename=~/ERROR:/){ println("ERROR: could not get last sheet, for:<br/><br/>$filename"); }
		elsif($filename!~/\S/){ println("ERROR: no csv sheet given!"); }
		elsif(! -f $filename){ println("ERROR: csv sheet ($filename) does not exist!"); }
		else{
			system("echo \"$filename\" >$tmpfile2"); # to enable "last" as sheet
			println("- going to $entry sheet $filename ...");
			printFocus("money", "$entry");
			if($entry eq "display"){
				@lines = getLinesOfFile($filename);
				println("<form onsubmit='return false'><textarea rows='30' cols='160' name='categories'>");
				println(join("\n", @lines));
				println("</textarea></form>");
			} else{
				@lines = getCommandOutput("$moneyhandlerbook $filename");
				$errornr = 0; $errfile = ""; $hasFatal = 0; $lnr = 0;
				for($l=0;$l<$#lines+1;$l++){
					$line = $lines[$l];
					next if($line=~/go through/ or $line!~/\S/);
					push(@oklines, $line) if($line!~/^\d+ error/i);
					next if($line=~/;/);
					if($line=~/ERROR:/){
						$hasFatal = $line;
						next;
					}
					$errornr = $1 if($line=~/^(\d+)\s+error/i);
					$errfile = $1 if($line=~/^check\s+(\S+)$/i);
				}
				if($errornr==0 && !$hasFatal){
					println("OK! No errors occurred!");
					println("- click here to merge it with the queue: <button onclick=\"document.location.href='/cgi-bin/bubu?interface=money&entry=merge&sheet=$filename';\">&nbsp;&nbsp;&nbsp;Merge&nbsp;&nbsp;&nbsp;</button>");
					open(O, ">$moneydir/Queue.lasttest.csv") or die("ERROR: cannot write file: $!");
					print O join("\n", @oklines);
					close(O);
				} elsif("$hasFatal" ne "0"){
					println("There was a fatal error: $hasFatal");
				} else{ # $errornr >0
					@lines = getLinesOfFile($errfile);
					println("- there have been $errornr errors, here are the problematic lines:");
					println(join("\n", @lines));
					println("- click here to edit the categories: <button onclick=\"document.location.href='/cgi-bin/bubu?interface=money&entry=category';\">&nbsp;&nbsp;&nbsp;Edit&nbsp;&nbsp;&nbsp;</button>");
				}
			}
		}
	}
	elsif($entry eq "assets" or $entry eq "taxtrend" or $entry eq "taxdata" or $entry eq "salarytrend" or $entry eq "boschprovision" or $entry eq "sdk_life" or $entry eq "sdk_pension"){
		$w = "assets";
		$f = "$sdir/assets.txt";
		$w = "taxes" if($entry eq "taxtrend");
		$f = "$sdir/taxtrend.txt" if($entry eq "taxtrend");
		$w = "taxdata" if($entry eq "taxdata");
		$f = "$sdir/taxdata.txt" if($entry eq "taxdata");
		$w = "salaries" if($entry eq "salarytrend");
		$f = "$sdir/salarytrend.txt" if($entry eq "salarytrend");
		$w = "provision" if($entry eq "boschprovision");
		$f = "$sdir/BoschProvision.txt" if($entry eq "boschprovision");
		$w = "SDK_Life" if($entry eq "sdk_life");
		$f = "$sdir/sdk_leben.txt" if($entry eq "sdk_life");
		$w = "SDK_Pension" if($entry eq "sdk_pension");
		$f = "$sdir/sdk_rente.txt" if($entry eq "sdk_pension");
		printHead("Edit $w");
		println("File $f ...");
		printFocus("money", "$entry") if($interface eq "money");
		if(checkSpecialPassword($password)){
			println("<form action='/cgi-bin/bubu?interface=money&entry=${entry}save&password=$password' method='post'><textarea rows='30' cols='180' name='$w'>");
			@lines = getLinesOfFile($f);
			println(join("\n", @lines));
			println("</textarea><br/><br/><button onclick=\"parent.loadPageWithConfirm('Sure to save?', 'form', self.document.forms[0]);\"> Save </button><br/><br/></form>");
		} else{
			println("Not allowed.");
		}
	}
	elsif($entry eq "assetssave" or $entry eq "taxtrendsave" or $entry eq "taxdatasave" or $entry eq "salarytrendsave" or $entry eq "boschprovisionsave" or $entry eq "sdk_lifesave" or $entry eq "sdk_pensionsave"){
		$e = $entry;
		$e =~ s/save//;
		$w = "assets";
		$f = "$sdir/assets.txt";
		$w = "taxes" if($entry eq "taxtrendsave");
		$f = "$sdir/taxtrend.txt" if($entry eq "taxtrendsave");
		$w = "taxdata" if($entry eq "taxdatasave");
		$f = "$sdir/taxdata.txt" if($entry eq "taxdatasave");
		$w = "salaries" if($entry eq "salarytrendsave");
		$f = "$sdir/salarytrend.txt" if($entry eq "salarytrendsave");
		$w = "provision" if($entry eq "boschprovisionsave");
		$f = "$sdir/BoschProvision.txt" if($entry eq "boschprovisionsave");
		$w = "SDK_Life" if($entry eq "sdk_lifesave");
		$f = "$sdir/sdk_leben.txt" if($entry eq "sdk_lifesave");
		$w = "SDK_Pension" if($entry eq "sdk_pensionsave");
		$f = "$sdir/sdk_rente.txt" if($entry eq "sdk_pensionsave");
		printHead("Save $w");
		if(checkSpecialPassword($password)){
			$filename = postIntoFile(1024*1024*5, "$w", "$f");
			if($filename!~/^ERROR:/){
					println("- file $filename has been posted, switching to $w ...");
					printRedirect("/cgi-bin/bubu?interface=money&entry=$e&password=$password", "wait");
			} else{
					println($filename);
			}
		} else{
			println("Not allowed.");
		}
	}
	elsif($entry eq "category"){
		printHead("Edit categories");
		printFocus("money", "category");
		println("<form action='/cgi-bin/bubu?interface=money&entry=catsave' method='post'><textarea rows='30' cols='140' name='categories'>");
		@lines = getLinesOfFile("$moneydir/findCategories.csv");
		println(join("\n", @lines));
		println("</textarea><br/><br/><button onclick=\"parent.loadPageWithConfirm('Sure to save?', 'form', self.document.forms[0]);\"> Save and test last sheet </button><br/><br/></form>");
	}
	elsif($entry eq "catsave"){
		printHead("Save categories");
		$filename = postIntoFile(1024*1024*5, "categories", "$moneydir/findCategories.csv");
				if($filename!~/^ERROR:/){
						println("- file $filename has been posted, switching to test ...");
						printRedirect("/cgi-bin/bubu?interface=money&entry=test&sheet=last", "wait");
				} else{
						println($filename);
				}
	}
	elsif($entry eq "merge"){
		printHead("Merge with queue");
		if($sheet!~/\S/){ println("ERROR: no sheet given!"); }
		elsif(! -f $sheet){ println("ERROR: sheet '$sheet' does not exist!"); }
		else{
			println("- merging $sheet with queue ...");
			$lfile = "$moneydir/Queue.lasttest.csv";
			$firstLine = `sed -n '1p' $lfile`; chomp($firstLine);
			$bank = $1 if($firstLine=~/^([^;]+);/);
			$qfile = "$moneydir/Queue.simon.csv";
			$qfile = "$moneydir/Queue.wei.csv" if($bank=~/wei/i);
			println("	- appending file of last test to queue $qfile ...");
			system("cat $lfile|grep ';' >>$qfile");
			system("cat $qfile|grep ';'|sort -u >$tmpfile; cp $tmpfile $qfile");
			println("- done, check $qfile");
		}
		printFocus("money", "merge");
	}
	elsif($entry eq "balance"){
		printHead("Insert bank balance");
		printFocus("money", "balance");
		$amount =~ s/,/./g;
		println("- bank: $bank, amount: $amount, date: $date");
		@lines = getLinesOfFile($balancefile);
		$isin = 0;
		for($l=0;$l<$#lines+1;$l++){
			$isin = 1 if($lines[$l] eq "$bank;$date;$amount");
		}
		if($isin){ println("- won't be added, since it is already in the file $balancefile!"); }
		else{
			println("	- add to $balancefile ...");
			open(F, ">$balancefile") or die("ERROR: cannot write $balancefile: $!");
			print F join("\n", @lines) ."\n$bank;$date;$amount";
			close(F);
			println("- has been added");
		}
	}
	elsif($entry eq "baledit"){
		printHead("<h2>Edit balances</h2>");
		println("<script language='javascript'>parent.focusType('money'); parent.focusSub('money', 'baledit');</script>");
		println("<form action='/cgi-bin/bubu?interface=money&entry=balsave' method='post'><textarea rows='30' cols='140' name='balances'>");
		@lines = getLinesOfFile($balancefile);
		println(join("\n", @lines));
		println("</textarea><br/><br/><button onclick=\"parent.loadPageWithPassword('form', document.forms[0]);\">Save balances</button><br/><br/></form>");
	}
	elsif($entry eq "balsave"){
		printHead("Save balances");
		if(checkSpecialPassword($password)){
			$filename = postIntoFile(1024*1024*5, "balances", "$balancefile");
					if($filename!~/^ERROR:/){
							println("- file $filename has been posted, switching to edit ...");
							printRedirect("/cgi-bin/bubu?interface=money&entry=baledit&password=$password", "wait");
					} else{
							println($filename);
					}
		} else{
			println("Not allowed.");
		}
	}
	elsif($entry eq "queueedit"){
		printHead("Edit queue of account '$sheet'");
		printFocus("money", "queueedit");
		println("<form action='/cgi-bin/bubu?interface=money&entry=queuesave&sheet=$sheet' method='post'><textarea rows='30' cols='140' name='queue'>");
		println(join("\n", sort(arrayUnique(getLinesOfFile("$moneydir/Queue.$sheet.csv")))));
		println("</textarea><br/><br/><button onclick=\"parent.loadPageWithConfirm('Sure to save?', 'form', self.document.forms[0]);\"> Save queue </button><br/><br/></form>");
	}
	elsif($entry eq "queuesave"){
		printHead("Save queue of account '$sheet'");
		$filename = postIntoFile(1024*1024*5, "queue", "$moneydir/Queue.$sheet.csv");
				if($filename!~/^ERROR:/){
						println("- file $filename has been posted, switching to edit ...");
						printRedirect("/cgi-bin/bubu?interface=money&entry=queueedit", "wait");
				} else{
						println($filename);
				}
	}
	elsif($entry eq "queuedelete"){
		printHead("Delete queue of account '$sheet'");
		printFocus("money", "queuedelete");
		$qfile = "$moneydir/Queue.$sheet.csv";
		die("ERROR: queue file $qfile does not exist!") if(! -f $qfile);
		system(">$qfile");
		println("OK! Queue file $qfile has been deleted!");
	}
	elsif($entry eq "insert"){
		printHead("Insert queue files");
#		$lastBook = `$moneyhandler balance all 2>&1|grep -i "last booking of all"|cut -d: -f2|awk '{print $1}'`;
		println("- the last booking was at: $lastBook");
		$qfile1 = "$moneydir/Queue.simon.csv";
		$qfile2 = "$moneydir/Queue.wei.csv";
		println("- insert queue of at first 'simon' ($qfile1), and then 'wei' ($qfile2) ...");
		system("$moneyhandler insert $qfile1 $lastBook >$tmpfile 2>&1");
		system("$moneyhandler insert $qfile2 $lastBook >>$tmpfile 2>&1");
		$lastBook = `$moneyhandler balance all 2>&1|grep -i "last booking of all"|cut -d: -f2|awk '{print $1}'`;
		println("- now the last booking is at: $lastBook");
		$balance = `$moneyhandler balance all 2>&1|grep -i "balance of all accounts"|cut -d: -f2|awk '{print $1}'`;
		println("- balance of all accounts is: $balance");
		println("- here are the bookings: <button onclick=\"with(document.getElementById('log').style){ display='block'; visibility='visible';}\">Show</button><div id='log' style='visibility:hidden;display:none'>");
		print `cat $tmpfile`;
		println("</div>");
	}
	elsif($entry eq "compensate"){
		printHead("Compensate with balances");
		$cdateNr = $cdate; # passed as argument
		$cdateNr =~ s/\-//g;
		@lines = getLinesOfFile($balancefile);
		for($l=0;$l<$#lines+1;$l++){
			($bank, $date, $amount) = split(/\s*;\s*/, $lines[$l]);
			$dateNr = $date;
			$dateNr =~ s/\-//g;
			$bankDates{$bank} = $amount if($dateNr>=$cdateNr and !exists($bankDates{$bank}) and $bank!~/^mmex/);
		}
		@bdkeys = keys(%bankDates);
		if($#bdkeys<0){
			println("ERROR: no balance defined which is at least of $cdate!");
		} else{
			foreach $bdkey(@bdkeys){
				$amount = $bankDates{$bdkey};
				println("- bank $bdkey: ". $amount);
				system("$moneyhandler compensate $bdkey $amount $cdate");
			}
		}
	}
	elsif($entry eq "update"){
		printHead("Update with balances");
		@bdkeys = ("simon", "wei", "dkb", "1822", "all");
		foreach $bdkey(@bdkeys){
			println("- bank $bdkey ...");
			@lines = getCommandOutput("$moneyhandler balance $bdkey");
			for($l=0;$l<$#lines+1;$l++){
				$bal = $lines[$l] if($lines[$l]=~/balance/i);
			}
			$bal =~ s/^.*balance of a?l?l? ?accounts?.+: ([\d\.]+)$/$1/i;
			println("	- balance: $bal");
			$todayM = `date +%Y-%m-%d`; chomp($todayM);
			system("echo 'mmex_$bdkey;$todayM;$bal' >>$balancefile");
			println("		- has been added into $balancefile!");
		}
	}
	elsif($entry eq "transactions"){
		printHead("Transactions file");
		printFocus("money", "transactions");
		println("<form action='' onsubmit=\"return false;\"><textarea rows='30' cols='140' name='transactions'>");
		println(join("\n", getLinesOfFile("$sdir/handleMoneyManager.Transactions.csv")));
		println("</textarea><br/><br/></form>");
	}
	elsif($entry eq "download"){
		printHead("Download database");
		printFocus("money", "download");
		println("<script language='javascript'>function downloadURI(uri, name){ var link = document.createElement('a'); link.download = name; link.href = uri; document.body.appendChild(link); link.click(); document.body.removeChild(link); delete link; }</script>");
		$orgdir = "$pidir/mmex";
		$dbfile = "Bruegmann.20200414.mmb";
		system("cp $orgdir/$dbfile $sharedir/");
		println("- The database file <a href='$sharedirwww/$dbfile'>'$sharedirwww/$dbfile'</a> is offered ...");
		println("<script language='script'>downloadURI('$sharedirwww/$dbfile', '$dbfile');</script>");
	}
	elsif($entry eq "salary"){
		printHead("Bosch salary");
		printRedirect("/BoschSalary.htm");
	}
	elsif($entry eq "growth"){
		printHead("Growth overview");
		printRedirect("/Wealth.htm");
	}
	elsif($entry eq "saledit"){
		printHead("Edit salary");
		println("<form action='/cgi-bin/bubu?interface=money&entry=salsave' method='post'><textarea rows='30' cols='140' name='salary'>");
		println(join("\n", getLinesOfFile("$sdir/BoschSalary.htm")));
		println("</textarea><br/><br/><button onclick=\"parent.loadPageWithPassword('form', document.forms[0]);\">Save salary</button><br/><br/></form>");
	}
	elsif($entry eq "salsave"){
		printHead("Save salary");
		if(checkSpecialPassword($password)){
			$filename = postIntoFile(1024*1024*10, "salary", "$sdir/BoschSalary.htm");
					if($filename!~/^ERROR:/){
							println("- file $filename has been posted, switching to show ...");
							printRedirect("/BoschSalary.htm", "wait");
					} else{
							println($filename);
					}
		} else{
			println("Not allowed");
		}
	}
	elsif($entry eq "weledit"){
		printHead("Edit growth");
		println("<form action='/cgi-bin/bubu?interface=money&entry=welsave' method='post'><textarea rows='30' cols='140' name='wealth'>");
		println(join("\n", getLinesOfFile("$sdir/Wealth.htm")));
		println("</textarea><br/><br/><button onclick=\"parent.loadPageWithPassword('form', document.forms[0]);\">Save growth</button><br/><br/></form>");
	}
	elsif($entry eq "welsave"){
		printHead("Save growth");
		if(checkSpecialPassword($password)){
			$filename = postIntoFile(1024*1024*10, "wealth", "$sdir/Wealth.htm");
					if($filename!~/^ERROR:/){
							println("- file $filename has been posted, switching to show ...");
							printRedirect("/Wealth.htm", "wait");
					} else{
							println($filename);
					}
		} else{
			println("Not allowed");
		}
	}
	printFoot() if(!$skipEnd);
}

if($interface eq "settings"){
	if($entry=~/^list_(.+)$/){
		$host = $1;
		printHead("List settings of $host");
		printFocus("settings", "list");
		println("<form><pre>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$cmd = "$libhandler -a list -r $host";
		$cmd .= " -f \"$filter\"" if($filter=~/\S/);
		@lines = getCommandOutput($cmd);
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='80'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">Save</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; formobj.action=\"/cgi-bin/bubu?interface=settings&entry=change&host=$host&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=$filter\"; parent.loadPageWithPassword('form', formobj);}</script>");
	}
	elsif($entry eq "spread"){
		printHead("Spread main library to hosts");
		println("Note: this is automatically done every minute via crontab");
		if(checkSpecialPassword($password)){
			for($h=0;$h<$#allhosts+1;$h++){
				$host = $allhosts[$h];
				next if($host eq "smarthome");
				printCommandAjax("scp $hdir/library.sh $host:$hdir/smarthome.lib.sh");
			}
		} else{
			println("Not allowed");
		}
	}
	elsif($entry eq "change"){
		printHead("Change setting");
		$ok = 1;
		$ok = 0 if($entry!~/upload/ and !checkSpecialPassword($password));
		if($ok){
			$value = urldecode($value);
			@lines = getCommandOutput("$libhandler -a change -r $host -s $setting -p \"". $value ."\"");
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$iserr = 1 if($line=~/ERROR/);
				println($line);
			}
			println("OK! Setting '$setting' has been changed to \"". $value ."\"") if(!$iserr);
			printRedirect("/cgi-bin/bubu?interface=settings&entry=list_$host&host=$host&filter=$filter&password=$password", "wait");
		}
	}
	elsif($entry eq "emailpw"){
		printHead("Change email password");
		if(checkSpecialPassword($password)){
			my $cmd = "sudo perl -p -i -e 's/password.+\\\$/password ". urldecode($newpw) ."/' /etc/msmtprc";
			printCommandOutput("smarthome:$cmd");
			printCommandOutput("rooftop:$cmd");
			printCommandOutput("factory:$cmd");
			printCommandOutput("garage:$cmd");
			println("OK! The password has been changed");
		} else{
			println("Not allowed");
		}
	}
	printFoot();
}

if($interface eq "energy"){
	$action = "show";
	$action = "edit" if($entry=~/_edit/);
	$action = "save" if($entry=~/_save/);
	$entry =~ s/_[a-z]{4}$//;
	$word = uc(substr($entry, 0, 1)) . substr($entry, 1);
	printHead("$word consumption");
	$cfile = "$sdir/energy.$entry.csv";
	$ifile = "$sdir/energy.$entry.txt";
	if($action eq "show"){
		println("<textarea name='info' rows='12' cols='140'>");
		println(join("\n", getLinesOfFile($ifile)));
		println("</textarea><br/><br/>");
		println("<table border='0' cellpadding='0' cellspacing='10'>");
		println("<tr><td><b>Date</b></td>
		<td><b>Meter</b></td>
		<td><b>Consumption/Day</b></td>
		<td><b>Consumption/Month</b></td>
		<td><b>Last year</b></td>
		<td><b>Consumption/Year</b></td>
		<td><button onclick=\"document.location.href='/cgi-bin/bubu?interface=energy&entry=${entry}_edit';\">&nbsp;Edit&nbsp;</button>&nbsp;<button onclick=\"showSheet()\">&nbsp;Show&nbsp;</button></td></tr>");
		$lastmeter = 99999999;
		$minmeter = $lastmeter; $mindate = "";
		require "$hdir/library.pl";
		@lines = getLinesOfFile($cfile);
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			($date, $meter) = split(/\s*;\s*/, $line);
			if($meter<$minmeter){
				$minmeter = $meter;
				$mindate = $date;
			}
			$dtmonth = $date;
			$dtmonth =~ s/^.*(\d\d\d\d)\-(\d\d).*$/$1$2/;
			$conPerDay = ""; $conPerMonth = ""; $conPerYear = "";
			if($lastmeter<$meter or $entry eq "food" or $entry eq "carrepair"){
				$dateTSnow = date2timestamp($date);
				$dateTSlast = date2timestamp($lastdate);
				$days = ($dateTSnow-$dateTSlast)/(24*3600);
				$conPerDay = ($meter-$lastmeter) / $days;
				$conPerMonth = sprintf("%.2f", $conPerDay * 30);
				$conPerYear = sprintf("%.2f", $conPerDay * 365);
				$conPerDay = sprintf("%.2f", $conPerDay);
				$conPerDay = 0 if(!$l);
				$conPerMonth = 0 if(!$l);
				$conPerYear = 0 if(!$l);
			}
			$conLastYears{$dtmonth} += $conPerMonth;
			$conLastYear = $conLastYears{$dtmonth-100};
			$diff = "";
			if($conLastYear=~/\S/ and $conPerMonth=~/\S/){
				push(@conPerMonths, $conPerMonth);
				$diff = sprintf("%.2f", $conPerMonth - $conLastYear);
				push(@diffValues, $diff);
			}
			push(@values, $date);
			push(@values, $meter);
			println("<tr><td>$date</td>
			<td>$meter</td>
			<td align='right'>$conPerDay</td>
			<td align='right'>$conPerMonth</td>
			<td align='right'>$diff</td>
			<td align='right'>$conPerYear</td>
			<td></td></tr>");
			$lastmeter = $meter;
			$lastdate = $date;
		}
		$datenow = `date +%Y-%m-%d`;
		chomp($datenow);
		$dateTSnow = date2timestamp($datenow);
		$dateTSlast = date2timestamp($mindate);
		$days = ($dateTSnow-$dateTSlast)/(24*3600);
		$conPerDay = ($meter-$minmeter) / $days;
		$conPerMonth = sprintf("%.2f", $conPerDay * 30);
		$conPerYear = sprintf("%.2f", $conPerDay * 365);
		$conPerDay = sprintf("%.2f", $conPerDay);
		println("<tr><td colspan='3'><br/>The last 6 months</td><td colspan='4'><br/>Compared to the year before</td></tr>");
		for($i=$#diffValues;$i>$#diffValues-6;$i--){
			$last6month += int($conPerMonths[$i]);
			$last6diff += int($diffValues[$i]);
		}
		$diff6per = sprintf("%.2f", $last6diff / $last6month * 100);
		println("<tr><td colspan='3'>$last6month</td><td colspan='4'>$last6diff: $diff6per %</td></tr>");
		println("<tr><td colspan='3'><br/>The last 12 months</td><td colspan='4'><br/>Compared to the year before</td></tr>");
		for($i=$#diffValues;$i>$#diffValues-12;$i--){
			$last12month += int($conPerMonths[$i]);
			$last12diff += int($diffValues[$i]);
		}
		$diff12per = sprintf("%.2f", $last12diff / $last12month * 100);
		println("<tr><td colspan='3'>$last12month</td><td colspan='4'>$last12diff: $diff12per %</td></tr>");
		println("<tr><td colspan='7'><br/>Overall (from $mindate, ". int($days) ." days: $minmeter)</td></tr>");
		println("<tr><td>$date</td><td>$meter</td><td align='right'>$conPerDay</td><td align='right'>$conPerMonth</td><td align='right' colspan='3'>$conPerYear</td></tr>");
		println("</table><script language='javascript'>function showSheet(){ window.open('/Energy.htm?type=$word&data=". join(",", @values) ."', 'energywin', 'fullscreen'); }</script>");
	}
	if($action eq "edit"){
		println("<form action='/cgi-bin/bubu?interface=energy&entry=${entry}_save' method='post'><textarea rows='20' cols='60' name='consumption'>");
		println(join("\n", getLinesOfFile($cfile)));
		println("</textarea><br/><br/><button onclick=\"parent.loadPageWithConfirm('Sure to save?', 'form', self.document.forms[0]);\"> Save </button></form>");
	}
	if($action eq "save"){
		$filename = postIntoFile(1024*1024*5, "consumption", "$cfile");
				if($filename!~/^ERROR:/){
						println("- file $filename has been posted, switching to test ...");
						printRedirect("/cgi-bin/bubu?interface=energy&entry=$entry", "wait");
				} else{
						println($filename);
				}
	}
	printFoot();
}

if($interface eq "garage"){
	if($entry eq "signal"){
		printHead("Garage signal");
		printCommandOutput("$hdir/garage_pusher.sh signal", "Send garage signal", "print", 1);
	}
	if($entry eq "block"){
		printHead("Block garage movement");
		printCommandOutput("garage:echo block >$hdir/garage.block");
	}
	if($entry eq "unblock"){
		printHead("Free garage movement");
		printCommandOutput("garage:echo active >$hdir/garage.block");
	}
	if($entry eq "correct"){
		printHead("Correct garage state");
		printCommandOutput("garage:$hdir/garage_setstatus.sh today now $state correct");
	}
	if($entry eq "list"){
		printHead("Garage movements");
		$comp = "garage_door";
		$bfile = "$hdir/garage.block";
		printSystemCommand("Blockage state", "timeout 15 ssh garage \"cat $bfile;\"|xargs echo _");
		println("- block file: $bfile");
		printSystemCommand("State", "$sofile -q state -c $comp");
		printSystemCommand("Last actions", "$sofile -q last50 -c $comp");
		printSystemCommand("Today's actions", "$sofile -q today -c $comp");
	}
	printFoot();
}

if($interface eq "water"){
	if($entry eq "settings"){
		printHead("Garden water settings");
		printFocus("water", "settings");
		println("<form method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$filter = "weather,rain,water,garage";
		@lines = getCommandOutput("$libhandler -a list -f $filter");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='40'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">&nbsp;Save&nbsp;</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; url=\"/cgi-bin/bubu?interface=water&entry=change&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=$filter\"; parent.loadPageWithPassword('form', formobj); }</script>");
	}
	elsif($entry eq "change"){
		printHead("Change a garden water setting");
		printFocus("water", "change");
		if(checkSpecialPassword($password)){
			$value = urldecode($value);
			$filter = "weather,rain,water,garage";
			@lines = getCommandOutput("$libhandler -a change -s $setting -p \"$value\"");
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$iserr = 1 if($line=~/ERROR/);
				println($line);
			}
			println("OK! Setting '$setting' has been changed to \"$value\"") if(!$iserr);
			printRedirect("/cgi-bin/bubu?interface=water&entry=settings&filter=$filter&password=$password", "wait");
		}
	}
	elsif($entry eq "list"){
		$use_garage = getLibrarySetting("use_garage");
		printHead("Runs of garden water");
		printFocus("water", "list");
		if($use_garage){
			# in host garage
			@lines = getCommandOutput("ssh garage \"grep garten_wasser $hdir/logs/execjob.*.log\"");
			# $hdir/logs/execjob.200818.log:081011: - close garten_wasser ...
			println("- these are the log entries of host garage:");
		} else{
			# local
			@lines = getCommandOutput("grep garten_wasser $hdir/logs/execcommand.*.log");
			# execcommand.200729.log:080005   - execute: ssh garage "$hdir/execjob.sh garten_wasser open 600" ...
			println("- these are the log entries of host smarthome (as garage is currently not in use):");
		}
		$iserr = 0; $nr=0;
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			if($line=~/(\d+)\.log:(\d+)\D\s+\-\s+(\S.+)$/){
				$d = "20$1";
				$t = $2;
				$c = $3;
				if($d=~/^(\d{4})(\d\d)(\d\d)$/){
					$d = "$1-$2-$3";
				}
				if($t=~/^(\d\d)(\d\d)(\d\d)$/){
					$t = "$1:$2:$3";
				}
				$c =~ s/\.+$//;
				$c =~ s/^.+garten_wasser/garten_wasser/ if(!$use_garage);
				$c =~ s/\"+\s*$// if(!$use_garage);
				push(@lines2, "$d $t $c");
			} elsif($line=~/^(\d{6}):\s+\-\s+(\S.+)$/){ # 080016: - open garten_wasser
				$t = $1;
				$c = $2;
				$d = $todayM;
				if($d=~/^(\d{4})\-?(\d\d)\-?(\d\d)$/){
					$d = "$1-$2-$3";
				}
				if($t=~/^(\d\d)(\d\d)(\d\d)$/){
					$t = "$1:$2:$3";
				}
				$c =~ s/\.+$//;
				$c =~ s/^.+garten_wasser/garten_wasser/ if(!$use_garage);
				$c =~ s/\"+\s*$// if(!$use_garage);
				push(@lines2, "$d $t $c");
			}
		}
		@lines2 = reverse(@lines2);
		for($f=0;$f<$#lines2+1;$f++){
			$line = $lines2[$f];
			$iserr = $line if($line=~/ERROR/);
			println($line);
			$nr++;
		}
		if($iserr){
			println("There was an error in the log files: $iserr");
		} 
		if($nr==0){
			println("There are no runs available!");
		}
	}
	elsif($entry eq "test" or $entry eq "stop"){
		$w = uc(substr($entry, 0, 1)) . substr($entry, 1);
		printHead("$w garden water");
		printFocus("water", "$entry");
		$d = $duration;
		$d = 0 if($entry eq "stop");
		$doit = 0;
		$doit = 1 if($entry eq "stop");
		$doit = 1 if($entry eq "test" and checkSpecialPassword($password));
		if($doit){
			$method = "fg";
			$method = "bg" if($d>100);
			@lines = getCommandOutput("$exfile -c garten_wasser:$d", $method);
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$iserr = 1 if($line=~/ERROR/);
				println($line);
			}
			if($iserr){
				println("There was an error");
			} else{
				$w = "tested";
				$w = "stopped" if($entry eq "stop");
				println("The garden water has been $w ...");
			}
		}
	}
	printFoot();
}

if($interface eq "marquee"){
	if($entry eq "settings"){
		printHead("Marquee settings");
		printFocus("marquee", "settings");
		println("<form method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$filter = "weather,rain,max";
		@lines = getCommandOutput("$libhandler -a list -f $filter");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='40'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">&nbsp;Save&nbsp;</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; url=\"/cgi-bin/bubu?interface=marquee&entry=change&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=$filter\"; parent.loadPageWithPassword('form', formobj); }</script>");
	}
	elsif($entry eq "change"){
		printHead("Change a marquee setting");
		printFocus("marquee", "change");
		$filter = "weather,rain,max";
		if(checkSpecialPassword($password)){
			$value = urldecode($value);
			@lines = getCommandOutput("$libhandler -a change -s $setting -p \"$value\"");
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$iserr = 1 if($line=~/ERROR/);
				println($line);
			}
			println("OK! Setting '$setting' has been changed to \"$value\"") if(!$iserr);
			printRedirect("/cgi-bin/bubu?interface=marquee&entry=settings&filter=$filter&password=$password", "wait");
		}
	}
	elsif($entry eq "block" or $entry eq "unblock"){
		$Entry = uc(substr($entry, 0, 1)) . substr($entry, 1);
		printHead("$Entry the marquee movement");
		$bfile = "$hdir/marquee.block";
		$bcont = "block";
		$bcont = "active" if($entry eq "unblock");
		println("- print $bcont into $bfile ...");
		system("echo \"$bcont\" >$bfile");
		$host = "smarthome";
		printSystemCommand("Blockage state", "timeout 15 ssh $host \"cat $bfile;\"|xargs echo _");
		println("- block file: $bfile");
	}
	elsif($entry eq "list"){
		printHead("Actions of marquee:");
		$bfile = "$hdir/marquee.block";
		$host = "smarthome";
		printSystemCommand("Blockage state", "timeout 15 ssh $host \"cat $bfile;\"|xargs echo _");
		println("- block file: $bfile");
		printFocus("marquee", "list");
		$comp = "markise_wintergarten";
		printSystemCommand("State", "$sofile -q state -c $comp");
		printSystemCommand("Last actions", "$sofile -q last10 -c $comp");
		printSystemCommand("Today's actions", "$sofile -q today -c $comp");
	}
	elsif($entry eq "marquee_on" or $entry eq "marquee_off"){
		$flag = "down";
		$flag = "up" if($entry=~/_off/);
		printHead("Put marquee $flag");
		$id = 1;
		$id = 0 if($flag eq "up");
		printFocus("marquee", "$entry");
		@lines = getCommandOutput("$exfile -c markise_wintergarten:$id -q");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			$iserr = 1 if($line=~/ERROR/);
			println($line);
		}
		if($iserr){
			println("There was an error");
		} else{
			println("The marquee has been put $flag ...");
		}
	}
	printFoot();
}

if($interface eq "alarmclock"){
	if($entry eq "show"){
		$bellSongDefault = "$pidir/Music/DonaldFagen/TheNightFly/WhatABeautifulTime.mp3";
		$pass = `cat $passfile 2>/dev/null`; chomp($pass);
		$iserr = 0;
		printHead("List alarmclock settings");
		printFocus("alarmclock", "show");
		println("<form action='/cgi-bin/bubu?interface=alarmclock&password=$pass&entry=upload' onsubmit='return false;' method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='0' border='0'>");
		@lines = getCommandOutput("$libhandler -a list -f bell");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><nobr><input type='text' name='bellSong' onfocus='this.select()' value=\"$value\" size='70'/><button onclick=\"parent.loadPageWithConfirm('Reset to default?', '/cgi-bin/bubu?interface=alarmclock&entry=change&password=$pass&setting=bellSong&value=$bellSongDefault');\">Default</button><button onclick=\"document.forms[0].bellSong.value=top.currentMediaPlayerFile;\">Current</button><input type='file'  name='song' onchange=\"\" accept='.mp3,.wav'/></nobr></td><td>$comment</td><td><button onclick=\"parent.loadPageWithConfirm('Upload song file?', 'form', document.forms[0]);\">Save</button></td></tr>") if($name eq "bellSong");
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='110'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">Save</button></td></tr>") if($name ne "bellSong");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; formobj.action=\"/cgi-bin/bubu?interface=alarmclock&entry=change&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=bell\"; parent.loadPageWithPassword('form', formobj);}</script>");
	}
	elsif($entry eq "change"){
		printHead("Change an alarmclock setting");
		printFocus("alarmclock", "change");
		if(checkSpecialPassword($password)){
			$value = urldecode($value);
			@lines = getCommandOutput("$libhandler -a change -s $setting -p \"$value\"");
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$iserr = 1 if($line=~/ERROR/);
				println($line);
			}
			println("OK! Setting '$setting' has been changed to \"$value\"") if(!$iserr);
			printRedirect("/cgi-bin/bubu?interface=alarmclock&entry=show&filter=bell&password=$password", "wait");
		}
	}
	elsif($entry eq "test"){
		printHead("Test the alarmclock song");
		printFocus("alarmclock", "test");
		@lines = getCommandOutput("$exfile -c wecker:1 -q");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			$iserr = 1 if($line=~/ERROR/);
			println($line);
		}
		if($iserr){
			println("There was an error");
		} else{
			println("The current song has been tested ...");
		}
	}
	elsif($entry eq "list"){
		printHead("Actions of bell:");
		printFocus("alarmclock", "list");
		$comp = "wecker";
		printSystemCommand("State", "$sofile -q state -c $comp");
		printSystemCommand("Last actions", "$sofile -q last50 -c $comp");
		printSystemCommand("Today's actions", "$sofile -q today -c $comp");
	}
	elsif($entry eq "stop"){
		printHead("Stop the alarmclock song");
		printFocus("alarmclock", "stop");
		@lines = getCommandOutput("ssh rooftop '$hdir/killsound.sh killbell'");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			$iserr = 1 if($line=~/ERROR/);
			println($line);
		}
		if($iserr){
			println("There was an error");
		} else{
			println("The current song has been stopped ...");
		}
	}
	elsif($entry eq "exceptionshow"){
		printHead("Exceptions of alarm clock");
		printSystemCommand("List exceptions", "$csfile $sdir/bellexceptions.csv show");
	}
	elsif($entry eq "exceptionadd"){
		printHead("Exceptions of alarm clock");
		$exceptionday = urldecode($exceptionday);
		if($exceptionday=~/^\d\d\d\d\-\d\d\-\d\d$/){
			printSystemCommand("Add '$exceptionday' to exceptions ...", "$csfile $sdir/bellexceptions.csv add $exceptionday; $csfile $sdir/bellexceptions.csv sort");
		}
		elsif($exceptionday=~/^(\d\d\d\d\-\d\d\-\d\d)[ \-,]{1,3}(\d\d\d\d\-\d\d\-\d\d)$/){
			$dayStart = $1;
			$dayEnd = $2;
			$dayStartTs = date2timestamp($dayStart);
			$dayEndTs = date2timestamp($dayEnd);
			if($dayEndTs<$dayStartTs){
				println("ERROR: 2nd date must be later than 1st date!");
			}
			else{
				while($dayStartTs<=$dayEndTs){
					$exceptionday = timestamp2date($dayStartTs);
					printSystemCommand("Add '$exceptionday' to exceptions ...", "$csfile $sdir/bellexceptions.csv add $exceptionday");
					$dayStartTs += 24*3600;
				}
				printSystemCommand("Sort exceptions ...", "$csfile $sdir/bellexceptions.csv sort");
			}
		}
		else{
			println("ERROR: format must be 'YYYY-MM-DD' or 'YYYY-MM-DD - YYYY-MM-DD'!");
		}
		printRedirect("/cgi-bin/bubu?interface=alarmclock&entry=exceptionshow", "wait");
	}
	elsif($entry eq "overwriteshow"){
		printHead("Overwrites of alarm clock");
		printSystemCommand("List overwrites", "$csfile $sdir/belloverwrites.csv show");
	}
	elsif($entry eq "overwriteadd"){
		printHead("Overwrites of alarm clock");
		$overwriteentry = urldecode($overwriteentry);
		if($overwriteentry!~/^\d\d\d\d\-\d\d\-\d\d \d\d:\d\d$/){
			println("ERROR: format must be 'YYYY-MM-DD HH:MM'!");
		} else{
			printSystemCommand("Add '$overwriteentry' to overwrites ...", "$csfile $sdir/belloverwrites.csv add '$overwriteentry'; $csfile $sdir/belloverwrites.csv sort");
			printRedirect("/cgi-bin/bubu?interface=alarmclock&entry=overwriteshow", "wait");
		}
	}
	elsif($entry eq "upload"){
		printHead("Alarm clock song upload");
		if(checkSpecialPassword($password)){
			$filename = uploadFile(1024 * 1024 * 10, "song", $sounddir);
			if($filename!~/^ERROR:/){
				println("- file $filename has been uploaded and move to directory $sounddir");
				$filebase = getBaseName($filename);
				@lines = getCommandOutput("scp $sounddir/$filebase pi\@rooftop:$sounddir");
				for($l=0;$l<$#lines+1;$l++){
					$line = $lines[$l];
					println("$line");
					$iserr = 1 if($line=~/could not resolve/i);
				}
				println("	- and been uploaded to rooftop") if(!$iserr);
				println("	- but has NOT been uploaded to rooftop") if($iserr);
				printRedirect("/cgi-bin/bubu?interface=alarmclock&entry=change&password=$pass&setting=bellSong&value=$sounddir/$filebase", "wait") if(!$iserr);
			} else{
 				println($filename);
			}
		}
	}
	printFoot();
}

if($interface eq "schedules"){
	$action = "show";
	if($entry=~/^(.+)?_(\D.+)?$/ and $entry!~/_[io][nu]t?$/){
		$entry = $1;
		$action = $2;
	}
	$Entry = uc(substr($entry,0,1)) . substr($entry, 1);
	$Entry =~ s/_/ /g;
	printHead("$Entry");
	$file = "$sdir/AWS-Abfallkalender_$todayY.pdf";
	$file = "$sdir/VVS.S1.Oesterfeld.BadCanstatt.pdf" if($entry eq "vvs_s1_in");
	$file = "$sdir/VVS.S1.Oesterfeld.Vaihingen.pdf" if($entry eq "vvs_s1_out");
	$file = "$sdir/VVS.S2.Oesterfeld.BadCanstatt.pdf" if($entry eq "vvs_s2_in");
	$file = "$sdir/VVS.S2.Oesterfeld.Vaihingen.pdf" if($entry eq "vvs_s2_out");
	$file = "$sdir/VVS.S3.Oesterfeld.BadCanstatt.pdf" if($entry eq "vvs_s3_in");
	$file = "$sdir/VVS.S3.Oesterfeld.Vaihingen.pdf" if($entry eq "vvs_s3_out");
	$file = "$sdir/VVS.U14.Engelbold.Muehlhausen.pdf" if($entry eq "vvs_u_in");
	$file = "$sdir/VVS.U14.Engelbold.Vaihingen.pdf" if($entry eq "vvs_u_out");
	$file = "$sdir/Holidays.BW.2025.htm" if($entry eq "holidays_2025");
	$file = "$sdir/Holidays.BW.2026.htm" if($entry eq "holidays_2026");
	$file = "$sdir/Holidays.BW.2027.htm" if($entry eq "holidays_2027");
	$file = "$sdir/Holidays.BW.2028.htm" if($entry eq "holidays_2028");
	$file = "$sdir/FeiertageBW.csv" if($entry eq "public");
	$file = "$sdir/Faschingsferien.csv" if($entry eq "fasching");
	$file = "$sdir/schedules.csv" if($entry eq "school");
	$file = "$sdir/VacationsBosch.csv" if($entry eq "bosch");
	$file = "$sdir/OnCall.csv" if($entry eq "oncall");
	$file = "$sdir/Sprints.csv" if($entry eq "sprints");
	$file = "$sdir/quotes.csv" if($entry eq "quotes");
	$file = "$sdir/jokes.csv" if($entry eq "jokes");
	if($entry eq "bible"){
		$file = "$sdir/bible.csv";
		$fieldLinks{"Verse"} = "/bible.htm?verse=%VALUE%";
	}
	$file = "$sdir/speedtest.csv" if($entry eq "speedtest");
	$file = "$sdir/birthdaytempl.txt" if($entry eq "remindertempl");
	if($entry=~/addresses/){
		$file = "$sdir/addresses.csv";
		$fieldLinks{"Address"} = "https://www.google.com/maps/place/%VALUE%";
	}
	$ext = lc(getFileExt($file));
	$base = getBaseName($file);
#printAndDie("- file $file, base $base, ext $ext"); 
	println("- file $file ...");
	if($ext eq "htm" or $ext eq "html" or $ext eq "pdf" or $ext eq "txt"){
		if($entry=~/holidays/){
			open(I, "<$file") or die("ERROR: cannot read file $file: $!");
			open(O, ">$sdir/WEBSHARE/$base") or die("ERROR: cannot write file $sdir/WEBSHARE/$base: $!");
			while(<I>){
				$line = $_;
				chomp($line);
				$line =~ s/(href=[\"'])/${1}https:\/\/schulferien.org/gi;
				$line =~ s/(src=[\"'])/${1}https:\/\/schulferien.org/gi;
				print O $line ."\n";
			}
			close(I);
			close(O);
		} else {
			system("cp $file $sdir/WEBSHARE");
		}
		if($ext eq "txt"){
			if($action eq "save" and checkSpecialPassword($password)){
				postIntoFile(1024 * 1024 * 5, "content", "$file");
			}
			println("<script language='javascript'>parent.focusType('schedules'); parent.focusSub('schedules', '$entry'); </script>");
			println("<form action='/cgi-bin/bubu?interface=schedules&entry=${entry}_save' method='post'><textarea rows='30' cols='140' name='content'>");
			println(join("\n", getLinesOfFile("$file")));
			println("</textarea><br/><br/><button onclick=\"parent.loadPageWithPassword('form', document.forms[0]);\">Save</button><br/><br/></form>");
		} else{
			println("<iframe width='100%' height='600' border='0' frameborder='0' src='/WEBSHARE/$base'></iframe>");
		}
	}
	elsif($ext eq "csv" and $action=~/save$/){
		$value = urldecode($value);
		$value =~ s/;/,:/gs;
		$value =~ s/\"/&quot;/gs;
		$value =~ s/'/&apos;/gs;
		$cmd = "$csfile $file edit $linenr $fieldnr \"$value\"";
		println("- exec: $cmd ...");
		system($cmd);
	}
	elsif($ext eq "csv" and $action=~/delete$/){
		$cmd = "$csfile $file delete $linenr";
		println("- exec: $cmd ...");
		system($cmd);
		printRedirect("/cgi-bin/bubu?interface=schedules&entry=$entry", 0);
	}
	elsif($ext eq "csv" and $action=~/random/){
		@lines = getLinesOfFile($file, 1);
		$caption = $lines[0];
		$pick = $lines[getRandomOfRange(1, $#lines)];
		chmod($caption);
		chmod($pick);
		@captions = split(/[;]/, $caption);
		@fields = split(/[;]/, $pick);
		for($f=0;$f<$#fields+1;$f++){
			$fields[$f] =~ s/,:/;/g;
		}
		printFocus("general", "${entry}_random");
		println("<table border='1' cellpadding='3' cellspacing='3' id='csvtable'>");
		println("<tr id='captions'><td>". join("</td><td>", @captions) ."</td></tr>");
		println("<tr id='fields'><td>". join("</td><td>", @fields) ."</td></tr>");
		println("</table>");
	}
	elsif($ext eq "csv" and $action=~/sort/){
		$cmd = "$csfile $file sort $fieldnr $sortmode";
		println("- exec: $cmd ...");
		system($cmd);
		printRedirect("/cgi-bin/bubu?interface=schedules&entry=$entry", 0);
	}
	elsif($ext eq "csv" and $action=~/add/){
		@lines = getLinesOfFile($file, 1);
		$captionline = $lines[0];
		$value = urldecode($value);
		$cmd = "$csfile $file add \"$captionline\"";
		println("- exec: $cmd ...");
		system($cmd);
		printRedirect("/cgi-bin/bubu?interface=schedules&entry=$entry", 0);
	}
	elsif($ext eq "csv"){
		use utf8::all;
		open I, "<:encoding(utf-8)", $file or die("ERROR: cannot read file $file: $!");
		while(<I>){
			$line = $_;
			chomp($line);
			@words = split(/[;]/, $line);
			$wnr = $#words + 1;
			$wmax = $wnr if($wnr>$wmax);
			push(@lines, $line);
		}
		close(I);
		printFocus("schedules", "$entry");
		println("<script language='javascript'>");
		println("function saveField(lid, fid, orgval){");
		println("	var xmlhttp = new XMLHttpRequest();");
		println("	var newval = document.getElementById(lid +'_'+ fid).innerText;");
		println("	xmlhttp.onreadystatechange = function(){ try{");
		println("		if(xmlhttp.readyState==4){");
		println("			if(xmlhttp.status>=200 && xmlhttp.status<300){");
		println("				document.getElementById('row_'+lid).style.backgroundColor='#5beb34'; window.setTimeout(\"document.getElementById('row_\"+lid+\"').style.backgroundColor='transparent';\", 1000); }");
		println("			else{");
		println("				document.getElementById('row_'+lid).style.backgroundColor='#c91e18'; window.setTimeout(\"document.getElementById('row_\"+lid+\"').style.backgroundColor='transparent';\", 1000);");
		println("				var t = 'ERROR: '+ xmlhttp.statusText;");
		println("				alert(t);");
		println("			}");
		println("		}");
		println("	} catch(ex){");
		println("		console.log(ex);");
		println("	}}");
		println("	if(newval!=orgval){");
		println("		xmlhttp.open('GET', '/cgi-bin/bubu?interface=schedules&entry=${entry}_save&linenr='+ (lid+1) +'&fieldnr='+ (fid+1) +'&value='+ encodeURIComponent(newval));");
		println("		xmlhttp.send();");
		println("}}");
		println("function sortBy(fieldid, fieldname, sortmode){");
		println("	if(confirm('Sure to sort by '+ fieldname +', mode '+ sortmode +'?')){ ");
		println("		document.getElementById('csvtable').innerHTML = \"<tr><td width='100%' align='center'>... wait for reply ...</td></tr>\";");
		println("		self.location.href='/cgi-bin/bubu?interface=schedules&entry=${entry}_sort&fieldnr='+ (fieldid+1) +'&sortmode='+ sortmode; }");
		println("}");
		println("function editRow(rowid){");
		println("	act='delete'; if(rowid==0) act='add'; if(confirm('Sure to '+ act +' a row?')){");
		println("		document.getElementById('capFilter').style.display='none';");
		println("		document.getElementById('filter').style.display='none';");
		println("		document.getElementById('csvtable').innerHTML = \"<tr><td width='100%' align='center'>... wait for reply ...</td></tr>\";");
		println("		self.location.href='/cgi-bin/bubu?interface=schedules&entry=${entry}_'+ act +'&linenr='+ (rowid+1); }");
		println("}");
		println("document.ondblclick=function(e){ e.stopPropagation(); e.cancelBubble = true; return false; }");
		println("var lastfilter=''; function applyFilter(){ var filter = document.getElementById('filter').value.replace(/^\\s+/g,'').replace(/\\s+\$/g,'');");
		println("	if(filter!=lastfilter){ for(t=0;t<document.getElementsByTagName('tr').length;t++) if(document.getElementsByTagName('tr')[t].id.match(/^row_(\\d+)/)){");
		println("	nr=RegExp.\$1; txt=document.getElementsByTagName('tr')[t].innerText; var dis='none'; if(nr==0) dis='table-row'; else if(filter=='') dis='table-row'; else if(txt.toLowerCase().indexOf(filter.toLowerCase())>=0) dis='table-row'; document.getElementsByTagName('tr')[t].style.display=dis; ");
		println("}} window.setTimeout('applyFilter()',50); lastfilter=filter; }");
		println("</script>");
		println("<span id='capFilter'>Filter </span><input type='text' id='filter' onfocus='applyFilter()'/>");
		println("<table border='1' cellpadding='3' cellspacing='3' id='csvtable'>");
		$nr = 0; $padding = "4px";
		for($n=0;$n<$#lines+1;$n++){
			$line = $lines[$n];
			chomp($line);
			next if($line!~/\S/);
			if($line=~/[,;]{15,200}/){
				$line =~ s/[,;]+//;
				println("<tr><td colspan='$wmax'>$line</td></tr>");
			} else {
				next if($line=~/ARRAY/);
				@fields = split(/[;]/, $line);
				if($nr==0){
					@captions = @fields;
					@avgs = @fields;
					for(my $f=0;$f<$#fields+1;$f++){
						$avgs[$f] = 0;
					}
				}
				$wmax = $#fields+1 if($nr==0);
				$contedit = "false";
				$contedit = "true" if($nr>0);
				$fontweight = "bold";
				$fontweight = "normal" if($nr>0);
				$tdalign = "center";
				$tdalign = "left" if($nr>0);
				$nextfield = $fields[0];
				$nextfid = 0;
				$line = "<tr id='row_$nr' title='row ". ($nr+1) ."'><td id='${nr}_$nextfid' align='$tdalign' contenteditable='$contedit' style='font-weight:$fontweight;padding:$padding' onblur=\"saveField($nr, $nextfid, '$nextfield')\">";
				for($f=0;$f<$#fields+1;$f++){
					$field = $fields[$f];
					if($field=~/^(\d[\.\d]*)\s\w[\/\w]+$/){
						$avgs[$f] += $1;
					}
					$field =~ s/,:/;/g;
					$nextfid = $f+1;
					$nextfield = $fields[$nextfid];
					$line .= "<img src='/images/sort.png' style='cursor:pointer' onclick=\"sortBy($f, '$field', 'asc')\" alt=\"Sort by '$field', mode 'asc'\" title=\"Sort by '$field', mode 'asc'\" border='0' height='20'/>&nbsp;" if($nr==0);
					$link = $fieldLinks{$captions[$f]};
					$link =~ s/%VALUE%/$field/g;
					$line .= "<span style='cursor:pointer' onclick=\"top.open('$link')\">" if($link=~/\S/);
					$line .= $field;
					$line .= "</span>" if($link=~/\S/);
					$line .= "<img src='/images/sortup.png' style='cursor:pointer' onclick=\"sortBy($f, '$field', 'desc')\" alt=\"Sort by '$field', mode 'desc'\" title=\"Sort by '$field', mode 'desc'\" border='0' height='20'/>" if($nr==0);
					$line .= "</td><td id='${nr}_$nextfid' align='$tdalign' contenteditable='$contedit' style='font-weight:$fontweight;padding:$padding' onblur=\"saveField($nr, $nextfid, '$nextfield')\">" if($f<$#fields);
				}
				$contbutton = "add";
				$contbutton = "delete" if($nr>0);
				$line .= "</td><td><button onclick=\"editRow($nr)\">$contbutton</button>";
				$line .= "&nbsp;<span id='info' style='font-weight:bold;font-size:xx-large'></span>" if($nr==0);
				$line .= "</td></tr>";
				println($line);
				$nr++;
			}
		}
		if($nr>1){
			println("<tr><td>");
			for($f=0;$f<$#fields+1;$f++){
				$avg = round2dec($avgs[$f] / ($nr-1));
				println($avg);
				println("</td><td>") if($f<$#fields);
			}
		}
		println("</tr></td>");
		println("<tr><td colspan='". ($wmax+1) ."' style='font-weight:$fontweight;padding:$padding'>". ($nr-1) ." lines</td></tr>");
		println("</table>");
	}
	printFoot();
}

if($interface eq "bible"){
	if($entry eq "search"){
		use utf8::all;
		$search = urldecode($search);
#		println("$sdir/bibleonline.pl $search");
		system("$sdir/bibleonline.pl $search 2>&1 >$tmpfile3");
		open F, "<:encoding(utf-8)", $tmpfile3;
		while(<F>){ print($_); }
		close(F);
		exit;
	}
}

if($interface eq "camera"){
	if($entry eq "settings"){
		printHead("Settings of cameras");
		printFocus("camera", "settings");
		println("<form method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='5' border='0'>");
		$filter = "cam";
		@lines = getCommandOutput("$libhandler -a list -f $filter");
		for($n=0;$n<$#lines+1;$n++){
			$line = $lines[$n];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='40'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">&nbsp;Save&nbsp;</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; formobj.action=\"/cgi-bin/bubu?interface=camera&entry=change&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=$filter\"; parent.loadPageWithPassword('form', formobj); }</script>");
		printFoot();
	}
	elsif($entry eq "configuration"){
		printHead("MotionEye Configuration");
		$f = "$sdir/motionconfiguration.txt";
		println("- configuration file: $f\n");
		$w = "configuration";
		if(checkSpecialPassword($password)){
			println("<form action='/cgi-bin/bubu?interface=camera&entry=configurationsave&password=$password' method='post'><textarea rows='30' cols='180' name='$w'>");
			@lines = getLinesOfFile($f);
			println(join("\n", @lines));
			println("</textarea><br/><br/><button onclick=\"parent.loadPageWithConfirm('Sure to save?', 'form', self.document.forms[0]);\"> Save </button><br/><br/></form>");
		} else{
			println("Not allowed.");
		}
		printFoot();
	}
	elsif($entry eq "configurationsave"){
		printHead("MotionEye Configuration");
		$f = "$sdir/motionconfiguration.txt";
		println("- configuration file: $f\n");
		$w = "configuration";
		if(checkSpecialPassword($password)){
			$filename = postIntoFile(1024*1024*5, "configuration", "$f");
			if($filename!~/^ERROR:/){
					println("- file $filename has been posted, switching to $w ...");
					printRedirect("/cgi-bin/bubu?interface=camera&entry=$w&password=$password", "wait");
			} else{
					println($filename);
			}
		} else{
			println("Not allowed.");
		}
		printFoot();
	}
	elsif($entry eq "configurationexport"){
		printHead("MotionEye Configuration");
		$f = "$sdir/motionconfiguration.txt";
		println("- export configuration by file $f ...\n");
		if(checkSpecialPassword($password)){
			$tmpdir = "$pidir/tmp/motioncfg";
			system("[ -d $tmpdir ] && rm -fr $tmpdir; mkdir $tmpdir");
			$camamount = getLibrarySetting("camAmount");
			$defheight = getLibrarySetting("camDefaultHeight");
			$defwidth = getLibrarySetting("camDefaultWidth");
			$singlecamswritten = 0; $code = "";
			open(F, "<$f") or printAndDie("ERROR: cannot read file $f: $!");
			while(<F>){
				$line = $_;
				chomp($line);
				if($line=~/^\s*FILE (.+):\s*$/){
					$filenamenew = $1;
					if(!$singlecamswritten){
						$singlecamswritten = 1;
						for($n=1;$n<=$camamount;$n++){
							$camcode = $code;
							$id = $n;
							$url = getLibrarySetting("camNr${n}Url");
							$tcp = getLibrarySetting("camNr${n}Tcp");
							$name = getLibrarySetting("camNr${n}Name");
							$user = getLibrarySetting("camNr${n}User");
							$port = getLibrarySetting("camNr${n}StrPort");
							$rotation = getLibrarySetting("camNr${n}Rotation");
							$width = $defwidth;
							$height = $defheight;
							if($rotation=~/90/ or $rotation=~/270/){
								$width = $defheight;
								$height = $defwidth;
							}
							$camcode =~ s/!ID!/$id/gs;
							$camcode =~ s/!URL!/$url/gs;
							$camcode =~ s/!TCP!/$tcp/gs;
							$camcode =~ s/!NAME!/$name/gs;
							$camcode =~ s/!USER!/$user/gs;
							$camcode =~ s/!PORT!/$port/gs;
							$camcode =~ s/!ROTATION!/$rotation/gs;
							$camcode =~ s/!WIDTH!/$width/gs;
							$camcode =~ s/!HEIGHT!/$height/gs;
							$camfile = "$tmpdir/camera-$n.conf";
							println("- write $camfile (name $name) ...");
							open(O, ">$camfile") or printAndDie("ERROR: cannot write file $camfile: $!");
							print O $camcode;
							close(O);
						}
					} else{
						println("- write $tmpdir/$filename ...");
						open(O, ">$tmpdir/$filename") or printAndDie("ERROR: cannot write file $tmpdir/$filename: $!");
						print O $code;
						close(O);
					}
					$code = "";
					$filename = $filenamenew;
				} else{
					$code .= $line ."\n";
				}
			}
			close(F);
			println("- write $tmpdir/$filename ...");
			open(O, ">$tmpdir/$filename") or printAndDie("ERROR: cannot write file $tmpdir/$filename: $!");
			print O $code;
			close(O);
			system("cd $tmpdir && tar czf motioneye-config.tar.gz * && mv motioneye-config.tar.gz $sharedir");
			println("- here is the link to the new configuration: <a href='$sharedirwww/motioneye-config.tar.gz' target='_blank'>$sharedirwww/motioneye-config.tar.gz</a>");
			printRedirect("$sharedirwww/motioneye-config.tar.gz");
#			for($n=1;$n<=$camamount;$n++){
#				system("cd $tmpdir && tar czf motioneye-config$n.tar.gz m* p* t* camera-$n.conf && mv motioneye-config$n.tar.gz $sharedir");
#				println("- here is the link to the new configuration: <a href='$sharedirwww/motioneye-config$n.tar.gz' target='_blank'>$sharedirwww/motioneye-config$n.tar.gz</a>");
#			}
		} else{
			println("Not allowed.");
		}
		printFoot();
	}
	elsif($entry eq "panel"){
		printHead("Camera panel");
		println("- login with cam/cam ...");
		$dom = $ENV{'HTTP_HOST'};
		$url = "http://cam:cam@". $dom ."/";
		println("<script language='javascript'>open('$url');</script>");
		println("<a href='$url' target='_blank'>Panel</a>");
		printFoot();
	}
	elsif($entry eq "change"){
		printHead("Change an camera setting");
		printFocus("camera", "settings");
		if(checkSpecialPassword($password)){
			$value = urldecode($value);
			$iserr = printCommandOutput("$libhandler -a change -s $setting -p \"$value\"");
			printP("OK! Setting '$setting' has been changed to \"$value\"") if(!$iserr);
		}
		printRedirect("/cgi-bin/bubu?interface=camera&entry=settings&filter=$filter&password=$password", "wait");
		printFoot();
	}
	$pdir = "/media/disc/Video/Smarthome/Camera";
	$Entry = uc(substr($entry, 0, 1)) . substr($entry, 1);
	printHead("Motion at camera $Entry");
	println("<script language='javascript'>function showImage(img){");
	println("with(document.getElementById('playerContainer')){ style.visibility='visible'; style.display='block'; style.opacity=''; style.position= '-webkit-sticky; sticky'; style.top='100'; innerHTML=\"<img id='mediaplayer' style='display:inline; position: -webkit-sticky, sticky; top:200;' src='/CAMERA/\"+ img +\"'/>\"; className='rotate$rot'; }");
	println("}</script>");
	println("<script language='javascript'>function showVideo(vid){");
	println("with(document.getElementById('playerContainer')){ style.visibility='visible'; style.display='block'; style.position='-webkit-sticky; sticky'; innerHTML = \"<video controls autoplay playsinline width='800' height='600'><source src='/CAMERA/\"+ vid +\"'/></video>\"; }");
	println("}</script>");
	println("<table cellpadding='0' cellspacing='5' border='0'><tr><td>");
	$filter = "winter";
	$filter = "front" if($entry eq "front");
	$filter = "entry" if($entry eq "entry");
	$pdir .= "/$Entry";
	@files = reverse(readDirectory($pdir));
	$fnr = 0; $vnr = 0;
	for($f=0;$f<$#files+1;$f++){
		$dir = getBaseName(getDirName($files[$f]));
		$size = getFileSize($files[$f], "human");
		$file = getBaseName($files[$f]);
		if($file=~/^(\d\d\d\d)(\d\d)(\d\d)\.(\d\d)(\d\d)(\d\d)\.jpg/){
			$fnr++; $n = $fnr; $n = "0$n" if($n<10);
			$y = $1; $m = $2; $d = $3; $H = $4; $M = $5; $S = $6;
#			println("$n) <span onclick=\"showImage('$dir/$file');\" onmousemove=\"showImage('$dir/$file');\" style='cursor:pointer'>$y-$m-$d at $H:$M:$S</span><br/><br/>");
		}
		elsif($file=~/^(\d\d\d\d)(\d\d)(\d\d)\.(\d\d)(\d\d)(\d\d)\.mp4/){
			# $dur = sec2time(getMediaDuration($files[$f]));
			$vnr++; $n = $vnr; $n = "0$n" if($n<10);
			$y = $1; $m = $2; $d = $3; $H = $4; $M = $5; $S = $6;
			println("$n) <span title='Click to view' onclick=\"showVideo('$dir/$file');\" style='cursor:pointer'>$y-$m-$d at $H:$M:$S ($size)</span><br/><br/>");
		}
		else{
#			println("$dir/$file");
		}
	}
	print ("</td><td valign='top'><div id='playerContainer' style='display:none;visibility:hidden'></div><div id='stage' style='display:none;visibility:hidden'></div></td></tr></table>");
	printFoot();
}

if($interface eq "speech"){
	if($entry eq "list"){
		printHead("List speech results");
		@lfiles = readDirectory("$sdir/logs");
		for($f=0;$f<$#lfiles+1;$f++){
			push(@logfiles, $lfiles[$f]) if($lfiles[$f]=~/speech2text.*.log/);
		}
		for($f=0;$f<$#logfiles+1;$f++){
			$logfile = $logfiles[$f];
			$logdate = $1 if($logfile=~/speech2text\.(\d+)\.log/);
			open(F, "<$sdir/logs/$logfile") or die("ERROR: cannot read logfile $logfile: $!");
			while(<F>){
				chomp($_);
				$line = $_;
				push(@loglines, "20$logdate $line") if($line=~/^\d+\s+RESULT/);
			}
			close(F);
		}
		@loglines = reverse(@loglines);
		$nr = 0;
		println("<form onsubmit='return false'><table cellspacing='5' cellpadding='0' border='0'>");
		println("<script language='javascript'>function interprete(nr){ df = document.forms[0]; txt = df.elements['text'+nr].value; parent.interprete(txt); }</script>");
		for($f=0;$f<$#loglines+1;$f++){
			$logline = $loglines[$f];
			$logline =~ s/ RESULT://;
			$logline =~ s/%HESITATION//;
			next if($logline=~/^\d+\s+\d+\s+$/);
			$nr++;
			last if($nr>20);
			if($logline=~/^(\d+)\s+(\d+)\s+(\S.+)$/){
				$ldate = $1;
				$ltime = $2;
				$lres = trim($3);
				println("<tr><td>$ldate $ltime</td><td><input type='text' value=\"$lres\" size='60' name='text$nr'/></td><td><button onclick=\"interprete('$nr')\">&nbsp;Interprete&nbsp;</button></td></tr>");
			}
		}
		println("</table></form>");
	}
	elsif($entry eq "interprete"){
		printHead("Interprete speech");
		printFocus("speech", "interprete");
		$txt = urldecode($txt);
		println("- text: $txt");
		println("- exec: $wordtest \"debugmode $txt\" ...");
		@lines = getCommandOutput("$wordtest \"debugmode $txt\"");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			println($line);
			if($line=~/the command is:\s+(\S.+)$/i){
				$foundcmd = $1;
			}
		}
		println("<script language='javascript'>parent.lastspeechcommand=\"$foundcmd\";</script>") if($foundcmd=~/\S/);
	}
	elsif($entry eq "reset"){
		printHead("Reset recent words");
		printFocus("speech", "reset");
		@lines = getCommandOutput("echo '' >$sdir/interprete.words");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			println($line);
			$err = 1 if($line=~/ERROR/i);
		}
		println("\nThere was an ERROR!") if($err);
		println("\nRecent words have been resetted") if(!$err);
	}
	elsif($entry eq "execute"){
		printHead("Execute speech");
		printFocus("speech", "execute");
		if(checkSpecialPassword($password)){
			$command = urldecode($command);
			$command =~ s/\s*\.*\s*$//;
			@lines = getCommandOutput($command);
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				println($line);
				$err = 1 if($line=~/ERROR/i);
			}
			println("\nThere was an ERROR!") if($err);
		}
	}
	elsif($entry eq "corrections"){
		printHead("Edit word corrections");
		println("<script language='javascript'>parent.focusType('speech'); parent.focusSub('speech', 'corrections'); function saveCorr(){ formobj=document.forms[0]; formobj.action='/cgi-bin/bubu?interface=speech&entry=corrsave'; parent.loadPageWithPassword('form', formobj);}</script>");
		println("<form method='post'><textarea rows='30' cols='140' name='corrections'>");
		println(join("\n", getLinesOfFile("$sdir/bubucorrections.csv")));
		println("</textarea><br/><br/><button onclick='saveCorr()'>&nbsp;Save corrections&nbsp;</button><br/><br/></form>");
	}
	elsif($entry eq "corrsave"){
		printHead("Save corrections");
		if(checkSpecialPassword($password)){
			postIntoFile(1024 * 1024 * 5, "corrections", "$sdir/bubucorrections.csv");
					if($filename!~/^ERROR:/){
							println("- file $filename has been posted, switching to test ...");
					} else{
							println($filename);
					}
		}
		printRedirect("/cgi-bin/bubu?interface=speech&entry=corrections&password=$password", "wait");
	}
	elsif($entry eq "commands"){
		printHead("Edit commands");
		println("<script language='javascript'>parent.focusType('speech'); parent.focusSub('speech', ''); function saveComm(){ formobj=document.forms[0]; formobj.action='/cgi-bin/bubu?interface=speech&entry=commsave'; parent.loadPageWithPassword('form', formobj);}</script>");
		println("<form method='post'><textarea rows='30' cols='140' name='commands'>");
		println(join("\n", getLinesOfFile("$sdir/bubucommands.csv")));
		println("</textarea><br/><br/><button onclick='saveComm()'>&nbsp;Save commands&nbsp;</button><br/><br/></form>");
	}
	elsif($entry eq "commsave"){
		printHead("Save commands");
		if(checkSpecialPassword($password)){
			postIntoFile(1024 * 1024 * 5, "commands", "$sdir/bubucommands.csv");
					if($filename!~/^ERROR:/){
							println("- file $filename has been posted, switching to test ...");
					} else{
							println($filename);
					}
		}
		printRedirect("/cgi-bin/bubu?interface=speech&entry=commands&password=$password", "wait");
	}
	elsif($entry eq "settings"){
		$pass = `cat $passfile 2>/dev/null`; chomp($pass);
		$iserr = 0;
		printHead("List speech settings");
		printFocus("speech", "settings");
		println("<form action='/cgi-bin/bubu?interface=speech&password=$pass&entry=change' method='post' enctype='multipart/form-data'>");
		println("<table cellpadding='0' cellspacing='0' border='0'>");
		@lines = getCommandOutput("$libhandler -a list -f btnRight,btnMiddle -r rooftop");
		for($l=0;$l<$#lines+1;$l++){
			$line = $lines[$l];
			println("$line") if($line=~/ERROR:/);
			next if($line!~/::/);
			($name, $value, $comment) = split(/\s*::\s*/, $line);
			$value = trim($value);
			println("<tr><td>$name</td><td><input type='text' name='$name' value=\"$value\" onblur=\"saveSetting('$name')\" onfocus='this.select()' size='110'/></td><td>$comment</td><td><button onclick=\"saveSetting('$name');\">Save</button></td></tr>");
		}
		println("</table></form><script language='javascript'>function saveSetting(name){ formobj = document.forms[0]; val=formobj.elements[name].value; formobj.action=\"/cgi-bin/bubu?interface=speech&entry=change&setting=\"+ name +\"&value=\"+ encodeURIComponent(val) +\"&filter=btnRight\"; parent.loadPageWithPassword('form', formobj);}</script>");
	}
	elsif($entry eq "change"){
		printHead("Change a speech setting");
		printFocus("speech", "settings");
		if(checkSpecialPassword($password)){
			$value = urldecode($value);
			@lines = getCommandOutput("$libhandler -a change -s $setting -p \"$value\" -r rooftop");
			for($l=0;$l<$#lines+1;$l++){
				$line = $lines[$l];
				$iserr = 1 if($line=~/ERROR/);
				println($line);
			}
			println("OK! Setting '$setting' has been changed to \"$value\"") if(!$iserr);
			printRedirect("/cgi-bin/bubu?interface=speech&entry=settings&filter=bell&password=$password", "wait");
		}
	}
	printFoot();
}







#### mediator: media interface faster 
if($mediator eq "browse" || $mediator eq "rename" || $mediator eq "delete" || $mediator eq "repairfilenames"){
	if($mediator eq "delete"){
		$dir = getDirName($entry);
		system("rm -f $entry") if($etype eq "file");
		$entrytxt = $entry;
		$entrydur = $entry;
		$entrytxt =~ s/\.\w\w\w\w?$/\.txt/;
		$entrydur =~ s/\.\w\w\w\w?$/\.dur/;
		system("rm -f $entrytxt") if(-e $entrytxt);
		system("rm -f $entrydur") if(-e $entrydur);
		system("rmdir $entry") if($etype eq "dir");
	}
	if($mediator eq "rename"){
		$orgtxt = $org;
		$orgdur = $org;
		$orgtxt =~ s/\.\w\w\w\w?$/\.txt/;
		$orgdur =~ s/\.\w\w\w\w?$/\.dur/;
		$newtxt = $new;
		$newdur = $new;
		$newtxt =~ s/\.\w\w\w\w?$/\.txt/;
		$newdur =~ s/\.\w\w\w\w?$/\.dur/;
		if(!-e $new){
			system("mv $org $new");
			system("mv $orgtxt $newtxt") if(-f $orgtxt);
			system("mv $orgdur $newdur") if(-f $orgdur);
		}
		$dir = getDirName($org);
	}
	if($mediator eq "repairfilenames"){
		$dir = resolveLink($dir);
		$orgdir = $dir;
		$cut = "/media/disc/Audio";
		$cut = "/media/disc/Video" if(index($dir, "/media/disc/Video")==0);
		$cut = "/media/disc/Pictures" if(index($dir, "/media/disc/Pictures")==0);
		$basedir = getBaseName($dir);
		$baseword = $basedir;
		$baseword =~ s/[^a-zA-Z0-9]/.*/g;
		$basedir2 = getBaseName(getDirName($dir));
		$baseword2 = $basedir2;
		$baseword2 =~ s/[^a-zA-Z0-9]/.*/g;
		@entries = readDirectory($dir);
		for($e=0;$e<$#entries+1;$e++){
				push(@files, $entries[$e]) if(-f $entries[$e]);
		}
		@bases = ();
		$duplicateNr = 1;
		for($f=0;$f<$#files+1;$f++){
				$file = $files[$f];
				$file =~ s/$cut\///;
				$base = getBaseName($file);
				$orgbase = $base;
				$ext = getFileExt($file);
				$base =~ s/\-_\-/_/g;
				$base =~ s/_([a-z][a-z])/&camelCase($1)/eg;
				$base =~ s/\-[a-zA-Z0-9_\-]{3,15}\.$ext/.$ext/ig;
				$base =~ s/[\(\)\[\]\{\}]//g;
				$base =~ s/[\-_]//g;
				$base =~ s/\.*_\-_/_/g;
				$base =~ s/[\-_]+\././g;
				$base =~ s/(by|from|of)$baseword//ig;
				$base =~ s/$baseword//ig;
				$base =~ s/(by|from|of)$baseword2//ig;
				$base =~ s/$baseword2//ig;
				$base =~ s/_//g;
				$base =~ s/^\-+//g;
				$base =~ s/\.+\.$ext$/.$ext/g;
				$base =~ s/~//g;
				$base =~ s/^\.+//g;
				$base = camelCase($base);
				$base =~ s/Ll/ll/g; # It'll would become ItLl, so it needs to be restored to Itll
				$base = "$baseword.$ext" if(lc($base) eq lc(".$ext") or lc($base) eq lc($ext));
				$tribe = getStemName($base);
				$base = "$tribe". $duplicateNr++ .".$ext" if(inArray($base, @bases));
				next if($base eq $orgbase);
				push(@orgbases, $orgbase);
				push(@bases, $base);
		}
		for($f=0;$f<$#orgbases+1;$f++){
			$orgbase = $orgbases[$f];
			$base = $bases[$f];
			system("mv $orgdir/$orgbase $orgdir/$base");
		}
	}
	$dir = resolveLink($dir);
	$dir = "/media/disc/Audio" if($dir!~/\media\/disc\/(Audio|Video|Pictures|Music)/);
	my @allfiles = ();
	printAndDie("Directory $dir not found: $!") if(!-e $dir);
	opendir(D, $dir);
	@entries = readdir(D);
	closedir(D);
	foreach my $entry(@entries){
		next if($entry eq "." or $entry eq ".." or $entry=~/^\./ or $entry eq "tmp");
		$isdir = 0; $isfile = 0;
		$isdir = 1 if(-d "$dir/$entry");
		$isfile = 1 if(-f "$dir/$entry");
		my $target = resolveLink("$dir/$entry");
		if($target){
			$isdir = 1 if(-d $target);
			$isfile = 1 if(-f $target);
		}
		next if($isfile and ($entry=~/\.txt$/i or $entry=~/\.sh$/i or $entry=~/\.pl$/i or $entry=~/\.out$/i or $entry=~/\.ini$/i or $entry=~/\.dur$/i));
		push(@files, $entry) if($isfile);
		push(@dirs, $entry) if($isdir);
	}
	if($byTime eq "true"){
		@files = ();
		system("ls -1t $dir|egrep -i \"\.mp3|\.mp4|\.jpg|\.jpeg|\.mov|\.png\" >/tmp/list.txt");
		open(F, "</tmp/list.txt");
		while(<F>){
			$line = $_;
			chomp($line);
			push(@files, $line);
		}
		close(F);
	}
	else{
		@files = sort(@files);
		@dirs = sort(@dirs);
	}
	$dirstr = join("!!", @dirs);
	$filestr = join("!!", @files);
	print $dirstr ."!__!". $filestr;
	exit 0;
}
if($mediator eq "searchFiles"){
	$dir = resolveLink($dir);
	$phrase = urldecode($phrase);
	@entries = readDirectories($dir);
	@files = ();
	foreach my $entry(@entries){
		next if($entry eq "." or $entry eq ".." or $entry=~/^\./);
		$entry = resolveLink($entry);
		next if(!-f $entry);
		push(@files, $entry) if($entry=~/$phrase/i);
	}
	if($dir=~/Audio/){
		@concats = dirFilterPos("txt", readDirectory($concatdir));
		for($c=0;$c<$#concats+1;$c++){
			$cfile = $concats[$c];
			$mfile = $cfile;
			$mfile =~ s/\.txt$/.mp3/i;
			open(F, "<$cfile") or printAndDie("ERROR: cannot read file $cfile: $!");
			while(<F>){
				chomp($_);
				($pos, $dur, $song) = split(/\s+/, trim($_));
				push(@files, "$mfile: $song") if($line=~/$phrase/i);
			}
			close(F);
		}
	}
	print join("!!", sort(arrayUnique(@files)));
	exit 0;
}
if($mediator eq "splitup"){
	$orgbase = getBaseName($orgfile);
	$tribe = getStemName($orgfile);
	$ext = lc(getFileExt($orgfile));
	$trackfile = "$dir/$tribe.txt";
	if($action eq "check"){
		$nr = 0;
		if(-f $trackfile){
			open(F, "<$trackfile");
			while(<F>){
				chomp($_);
				($pos, $dur, $name) = split(/\s+/, $_);
				$base = getBaseName($name);
				$nr++ if($_=~/\S/ and $base ne $orgbase);
			}
			close(F);
		}
		print $nr;
	}
	if($action eq "splitup"){
		$hour = 0; $lastpos = "";
		open(F, "<$trackfile");
		while(<F>){
			chomp($_);
			next if($_!~/\S/);
			($pos, $dur, $name) = split(/\s+/, $_);
			$hour++ if($lastpos ne "" and time2sec($pos)<time2sec($lastpos));
			$lastpos = $pos;
			$pos = d2($hour) .":$pos.000";
			$dur = "00:$dur.000";
			$subext = lc(getFileExt($name));
			$name .= ".$ext" if($subext!~/\S/);
			$subext = getFileExt($name);
			$subtribe = getStemName($name);
			next if("$dir/$orgbase" eq "$dir/$subtribe.$subext");
			$subfile = "$dir/$subtribe.$subext";
			system("mv $subfile $dir/$subtribe.$today.$now.$subext") if(-f $subfile);
			if($ext eq $subext){
				#system("ffmpeg -ss $pos -i $dir/$orgfile -t $dur -c copy $subfile &");
				printlg("ffmpeg -ss $pos -i $dir/$orgfile -t $dur -acodec libmp3lame $subfile &");
				system("ffmpeg -ss $pos -i $dir/$orgfile -t $dur -acodec libmp3lame $subfile &");
			} else{
				#system("ffmpeg -ss $pos -i $dir/$orgfile -t $dur -f mp3 -ab 192k -vn $subfile &");
				system("ffmpeg -ss $pos -i $dir/$orgfile -t $dur -f mp3 -acodec libmp3lame -vn $subfile &");
			}
		}
		close(F);
	}
	exit 0;
}
if($mediator eq "editduration"){
	$tribe = getStemName($file);
	$durfile = "$dir/$tribe.dur";
	if($subaction eq "edit"){
		if(-f $durfile){
			$duration = `cat $durfile`;
			chomp($duration);
		} else{
			$duration = getMediaDuration("$dir/$file");
			$duration = sec2time($duration);
		}
		print $duration;
	}
	if($subaction eq "save"){
		$content = urldecode($content);
		chomp($content);
		if(open(F, ">$durfile")){
			print F $content;
			close(F);
			print "OK";
		}
		else{
			print "ERROR";
		}
	}
	exit 0;
}
if($mediator eq "edittracklist"){
	$tribe = getStemName($file);
	$trackfile = "$dir/$tribe.txt";
	if($subaction eq "edit"){
		$content = "";
		if(-f $trackfile and open(F, '<:encoding(UTF-8)', $trackfile)){
			while(<F>){
				chomp($_);
				$content .= $_ ."\n";
			}
			close(F);
		}
		print $content;
	}
	if($subaction eq "save"){
		$content = urldecode($content);
		$content =~ s/<br\s*\/?>//gi;
		$content = calculateMediaPositions($trackfile, getMediaDuration("$dir/$file"), split(/\r?\n/, $content));
		if(open(F, ">$trackfile")){
			print F $content;
			close(F);
			print "OK";
		}
		else{
			print "ERROR";
		}
	}
	exit 0;
}
if($mediator eq "mediainfo"){
	$file = "$dir/$file" if($file!~/^\//);
	$songs = "";
	$txtfile = "$file";
	$txtfile =~ s/\.\w\w\w$/.txt/;
	if(-f $txtfile){
		$nr = 0;
		open(T, "<$txtfile") or printAndDie("ERROR: cannot read $txtfile: $!");
		while(<T>){
			chomp($_);
			($pos, $dur, $song) = split(/\s+/, trim($_));
			$song = getStemName($song);
			$nr++;
			$songs .= "$nr) $song&nbsp;&nbsp;&nbsp;$dur<br/>\n";
		}
		close(T);
	}
	$dur = sec2time(getMediaDuration("$file"));
	$rate = getAudioRate("$file");
	$alib = getAudioLibrary("$file");
	$size = getFileSize("$file");
	$last = timestamp2date(getFileLM("$file"));
	println("Duration: $dur, Audio rate: $rate, Library: $alib");
	println("<br/>\nLast modified: $last, File size: $size");
	println("<br/>\nSongs:<br/>\n". $songs) if($songs=~/\S/);
	exit 0;
}
if($mediator eq "convert2lame"){
	$file = getBaseName($file);
	$entry = "$dir/$file";
	if(-d $entry){
		@files = dirFilterPos("mp3", readDirectory($entry));
	} else{
		@files = ($entry);
	}
	for($f=0;$f<$#files+1;$f++){
		$fileorg = $files[$f];
		$filetmp = "$fileorg.tmp";
		$filecmd = "/tmp/convert2lame.cmd.". getRandomNumber(1000000) .".sh";
		open(T, ">$filecmd") or die("ERROR: cannot write file $filecmd: $!");
		print T "#!/bin/bash\n";
		print T "mv $fileorg $filetmp;\n";
		print T "lame --mp3input -v -V 2 $filetmp $fileorg; rc=\$?;\n";
		print T "[ \"\$rc\" = \"0\" ] && rm -f $filetmp\n";
		print T "[ \"\$rc\" != \"0\" ] && mv $filetmp $fileorg\n";
		close(T);
		system("chmod +x $filecmd");
		printlg("- converting $fileorg to lame by $filecmd ...");
		system("$filecmd &");
	}
	exit 0;
}
if($mediator eq "extract"){
	$entry = "$dir/". getBaseName($orgfile);
	if(-d $entry){
		@entries = readDirectory($entry);
		for($f=0;$f<$#entries+1;$f++){
			$file = $entries[$f];
			$ext = lc(getFileExt($file));
			push(@files, $file) if($ext eq "mp3" or $ext eq "mp4");
		}
		$dir = $entry;
	} else{
		@files = ($entry);
	}
	for($f=0;$f<$#files+1;$f++){
		$orgfile = $files[$f];
		$base = getBaseName($orgfile);
		$tribe = getStemName($orgfile);
		if("$dir/$base" ne "$dir/$tribe.mp3"){
		#	system("ffmpeg -i $dir/$base -q:a 0 -map a $dir/$tribe.mp3 &");
			printlg("- extracting audio by: ffmpeg -i $dir/$base -q:a 2 -acodec libmp3lame $dir/$tribe.mp3 &");
			system("ffmpeg -i $dir/$base -q:a 2 -acodec libmp3lame $dir/$tribe.mp3 &");
		}
	}
	exit 0;
}
if($mediator eq "getmediaduration"){
	print getMediaDuration($file);
	exit 0;
}
if($mediator eq "concatinfo"){
	@files = dirFilterPos("txt", readDirectory($concatdir));
	$filenr = 0; $linenr = 0; $totaldur = 0;
	for($f=0;$f<$#files+1;$f++){
		$file = $files[$f];
		next if(!-f $file or $file=~/\.swp/);
		open(F, "<$file") or next;
		$filenr++; $lastmin = 0; $hour = 0;
		while(<F>){
			chomp($_);
			$line = trim($_);
			next if($line!~/^\d+:\d\d \d+:\d\d /);
			$linenr++;
			($pos, $dur, $song) = split(/\s+/, $line);
			($min, $sec) = split(/:/, $pos);
			$min = int($min);
			$sec = int($sec);
			$hour++ if($min<$lastmin);
			$lastmin = $min;
			$pos = d2($hour) .":". d2($min) .":". d2($sec);
		}
		close(F);
		$concatdur = int(time2sec($pos)) + int(time2sec("00:$dur"));
		$totaldur += $concatdur;
	}
	$totaldur = sec2time($totaldur);
	println("$filenr concats, $linenr songs, duration of $totaldur");
	exit 0;
}
if($mediator eq "getfiles"){
	$maxlen = 50 if($maxlen!~/\S/); $fnr = 0;
	@files = readDirectories($dir);
	@files = shuffle(@files) if($sort eq "random");
	@newfiles = ();
	for($f=0;$f<$#files+1;$f++){
		$file = resolveLink($files[$f]);
		if(-e $file){
			push(@newfiles, $file);
			$fnr++;
		}
		last if($fnr>=$maxlen);
	}
	print join("!!", @newfiles);
	exit 0;
}
if($mediator eq "getSpecialPassword"){
	$pw = `cat $passfile|base64`;
	chomp($pw);
	print "$pw";
	exit 0;
}
if($mediator eq "testfile"){
	$realfile = "/home/pi/Music/$file";
	$realfile = "/media/disc/Audio/$file" if(-e "/media/disc/Audio/$file");
	$realfile = "/media/disc/Video/$file" if(-e "/media/disc/Video/$file");
	print $realfile;
	exit 0;
}
if($mediator eq "readtextfile"){
	$newfile = $file;
	$newfile =~ s/\.\w\w\w\w?$/\.txt/;
	if(-f $newfile){
		open(F, '<:encoding(UTF-8)', $newfile) or die("ERROR: cannot read $newfile: $!");
		while(<F>){
			$line = $_;
			chomp($line);
			push(@lines, $line) if($line=~/\S/ and $line!~/Array/i);
		}
		close(F);
		$line = join("\n", @lines);
		$line =~ s/Array\(\w+\)\r?\n?//gs;
		print $line;
	} else{
		print "";
	}
	exit 0;
}
if($mediator eq "readtxtfiles"){
	@files = readDirectory($dir);
	$allcont = "";
	for($f=0;$f<$#files+1;$f++){
		if($files[$f]=~/\.txt$/i){
			$txtfile = getBaseName($files[$f]);
			$txtstem = getStemName($files[$f]);
			for($g=0;$g<$#files+1;$g++){
				next if($files[$g]=~/\.txt$/i or $files[$g]=~/\.dur$/i);
				$medfile = getBaseName($files[$g]);
				$medstem = getStemName($files[$g]);
				$cont = "";
				if($txtstem eq $medstem){
					open(F, "<$dir/$txtfile") or next;
					$nr = 0;
					while(<F>){
						chomp($_);
						$line = trim($_);
						$line =~ s/[\"']//g;
						$cont .= " %%%" if($nr++);
						$cont .= $line;
					}
					close(F);
					$allcont .= "txtFileInfos['". ($medfile) ."'] = \"$cont\"; ";
				}
			}
		}
	}
	print $allcont;
	exit 0;
}
if($mediator eq "concat" or $mediator eq "genconcat"){
	if($mediator eq "genconcat"){
		@fileelems = split(/\s*,\s*/, $files);
		@files = ();
		for($f=0;$f<$#fileelems+1;$f++){
			$fileelem = $fileelems[$f];
			$fileelem =~ s/^\/[hm][oe][md][ei]a?\/[pd]is?c?\/[MAV][ui][sd][ie][co]\///;
			$realfile = "/home/pi/Music/$fileelem";
			$realfile = "/media/disc/Audio/$fileelem" if(-e "/media/disc/Audio/$fileelem");
			$realfile = "/media/disc/Video/$fileelem" if(-e "/media/disc/Video/$fileelem");
			push(@files, $realfile);
		}
		$maxlen = $audiomaxconcat if($maxlen!~/\S/);
	}
	elsif($files=~/\S/){
		@fileelems = split(/\s*,\s*/, $files);
		@files = ();
		for($f=0;$f<$#fileelems+1;$f++){
			push(@files, "$dir/". $fileelems[$f]);
		}
		$maxlen = $audiomaxconcat if($maxlen!~/\S/);
	} else{
		@files = readDirectories($dir);
		@files = shuffle(@files) if($sort eq "random");
		$maxlen = $audiomaxshuffle if($maxlen!~/\S/);
	}
	$datestr = `date +%Y%m%d%H%M%S`; chomp($datestr);
	$concatfile = "$concatdir/Concat.$datestr.". ($#files+1) .".mp3";
	$concatfileW = "$concatdir/Concat.$datestr.". ($#files+1) ."_MP3WRAP.mp3";
	$contxtfile = "$concatdir/Concat.$datestr.". ($#files+1) .".txt";
	$concmdfile = "$concatdir/Concat.$datestr.". ($#files+1) .".cmd";
	$concmdfile2 = "$concatdir/Concat.$datestr.". ($#files+1) .".cmd2";
	@newfiles = (); @mp3files = (); $fnr = 0; $pos = 0;
	open(C, ">$concmdfile") or die("ERROR: cannot write $concmdfile: $!");
	print C "#!/bin/bash\n";
	open(T, ">$contxtfile") or die("ERROR: cannot write $contxtfile: $!");
	for($f=0;$f<$#files+1;$f++){
		$file = resolveLink($files[$f]);
		next if(!-e $file);
		$ext = lc(getFileExt($file));
		$fnr++;
		last if($fnr>$maxlen);
		if($ext eq "mp4"){
			$newfile = "$concatdir/tmp/". getStemName($file) .".mp3";
			print C "if [ ! -f $newfile ]; then\n";
			#print C "  ffmpeg -i ". $file ." -b:a 192K -vn $newfile >/dev/null 2>&1; [ \"$?\" != \"0\" ] && rm -f $newfile\n";
			print C "  ffmpeg -i ". $file ." -acodec libmp3lame -vn $newfile >/dev/null 2>&1; [ \"$?\" != \"0\" ] && rm -f $newfile\n";
			print C "fi\n";
			push(@mp3files, $newfile);
			$ext = "mp3";
		} elsif($ext eq "mp3"){
			push(@mp3files, $file);
		}
# ffmpeg -i /media/disc/Audio/DonaldFagen/TheNightFly/WhatABeautifulTime.mp3 2>&1|grep Duration|awk '{print $2}'
# 00:06:02.89,
		$mp3dur = `ffmpeg -i $file 2>&1|grep Duration|awk '{print \$2}'`;
		$mp3dur =~ s/[\s,]+//gs;
		$mp3sec = time2sec($mp3dur);
		$mp3dur =~ s/^\d\d:(\d\d:\d\d)\.?\d*$/$1/;
		$mp3pos = sec2time($pos);
		$mp3pos =~ s/^\d\d:(\d\d:\d\d)\.?\d*$/$1/;
		$short = $file;
		$short =~ s/\/media\/disc\/Audio\///;
		$line = "$mp3pos $mp3dur $short";
		print T "$line\n" if($line!~/ARRAY/i);
		$pos += $mp3sec;
		push(@newfiles, $file) if($ext ne "mp3");
	}
	close(T);
	print C "mp3wrap $concatfile ". join(" ", @mp3files) ." >/dev/null 2>&1\n";
	print C "mv $concatfileW $concatfile\n";
	print C "bash -c 'sleep 3; rm -f $concmdfile $concmdfile2' &\n";
	unshift(@newfiles, $concatfile) if(-e $concatfile);
	unshift(@newfiles, $contxtfile) if(-e $contxtfile);
	print join("!!", @newfiles);
	close(C);
	system("chmod +x $concmdfile");
	open(C, ">$concmdfile2") or die("ERROR: cannot write $concmdfile2: $!");
	print C "#!/bin/bash\n";
	print C "$concmdfile &\n";
	close(C);
	system("chmod +x $concmdfile2");
	system("bash $concmdfile2");
	exit 0;
}
if($mediator eq "correctPosition"){ # callAjax("mediator=correctPosition&file="+ mediaFile +"&lineId="+ lineId +"&newPos="+ newPos +"&totalDur="+ mediaTotalSeconds);
	$txtfile = $file;
	$txtfile =~ s/\.\w{2,4}$/\.txt/;
	$filelineid = 0;
	open(T, "<$txtfile") or die("ERROR: cannot read $txtfile: $!");
	while(<T>){
		next if($_!~/\S/);
		$line = $_;
		chomp($line);
		if($lineId==$filelineid){
			($pos, $dur, $name) = split(/\s+/, trim($line));
			$line = "$newPos $dur $name";
		}
		$filelineid++;
		push(@lines, $line);
	}
	close(T);
	print calculateMediaPositions($txtfile, $totalDur, @lines);
	exit 0;
}
if($mediator eq "send2player"){
	$tmpfile = "/tmp/mediafiles.". getRandomNumber(1000000) .".$$.lst";
	$maxlen = 50 if($maxlen!~/\S/); $fnr = 0;
	open(T, ">$tmpfile") or die("ERROR: cannot write $tmpfile: $!");
	if($files!~/\S/){
		@files = readDirectories($dir);
		@files = shuffle(@files) if($sort eq "random");
		for($f=0;$f<$#files+1;$f++){
			$file = $files[$f];
			print T "$file\n";
			$fnr++;
			last if($fnr>=$maxlen);
		}
	} else{
		@files = split(/,/, $files);
		for($f=0;$f<$#files+1;$f++){
			$file = $dir ."/". $files[$f];
			$file = $files[$f];
			print T "$file\n";
			printlg("- printed file $file into $tmpfile");
			$fnr++;
			last if($fnr>=$maxlen);
		}
	}
	close(T);
	system("nohup $hdir/playerSender.sh -p $player -f $tmpfile >/dev/null 2>&1 &");
	printlg("nohup $hdir/playerSender.sh -p $player -f $tmpfile");
	print "$fnr files have been sent to $player";
	exit 0;
}
if($mediator eq "check"){
	if($player!~/\S/){
		printCommandAjax("ps -ef|egrep 'playAt[A-Z][a-z]*\.sh|playerSender\.sh|playsound\.sh'|grep -v grep|wc -l|awk '{print $1}'|xargs echo player processes:", "- check all player processes ...");
	} else{
		$playerWord = "Middle";
		$playerWord = "Roof" if($player eq "rooftop");
		$playerWord = "Factory" if($player eq "factory");
		$code = printCommandOutput("ps -ef|egrep 'playAt$playerWord\.sh|playerSender\.sh \-p $player'|grep -v grep|wc -l|awk '{print $1}'|xargs echo player processes:", "- check all player processes ...", "return"); # e.g. player processes: 0
		$processNr = $1 if($code=~/player processes: (\d+)$/);
		if($processNr==0){
			print "none";
		} else{
			$code = printCommandOutput("ps -ef|egrep 'playAt$playerWord\.sh'|grep -v grep", "- check song", "return");
			@words = split(/\s+/, $code);
			print $words[-1];
		}
	}
	exit 0;
}
if($mediator eq "mediacheck"){
	@lines = getCommandOutput("$host:ps -ef", "- checking media processes on $host ...<br/>");
	$nr = 0;
	for($i=0;$i<$#lines+1;$i++){
		$line = $lines[$i];
		next if($line!~/play/i and $line!~/mp3wrap/i and $line!~/ffmpeg/i and $line!~/concat/i and $line!~/youtube/i and $line!~/lame/i);
		($user, $pid, $ppid, $x, $time, $tty, $dur, @rest) = split(/\s+/, $line);
		$line = "$user <button onclick=\"document.location.href='/cgi-bin/bubu?mediator=mediaprockill&procid=$pid';\">kill $pid</button> $ppid $x $time $tty $dur ". join(" ", @rest);
		println($line ."<br/>");
		$nr++;
	}
	$killbutton = " <button onclick=\"document.location.href='/cgi-bin/bubu?mediator=mediaprockill&procid=all';\">kill all</button>";
	println("$nr processes". ($nr>0 ? $killbutton : ""));
	exit 0;
}
if($mediator eq "mediaprockill"){
	if($procid eq "all"){
		printCommandOutput("ps -ef|egrep -i \"play|mp3wrap|ffmpeg|concat|youtube\"|awk '{print \$2'}|xargs kill -9", "- kill all media processes ...");
	} else{
		printCommandOutput("kill -9 $procid", "- kill media process $procid ...");
	}
	exit 0;
}
if($mediator eq "pause" or $mediator eq "resume" or $mediator eq "play"){
	$mediator = "resume" if($mediator eq "play");
	$act = $mediator;
	$Act = uc(substr($act, 0, 1)) . substr($act, 1);
	if($player!~/\S/){
		printHead("$Act all playing songs ...");
		printCommandOutput("smarthome:/home/pi/smarthome/playcontrol.sh $act", "- $act player on smarthome ...");
		printCommandOutput("rooftop:/home/pi/smarthome/playcontrol.sh $act", "- $act player on rooftop ...");
		printCommandOutput("factory:/home/pi/smarthome/playcontrol.sh $act", "- $act player on factory ...");
	} else{
		printHead("$Act song of player $player ...");
		printCommandOutput("$player:/home/pi/smarthome/playcontrol.sh $act", "- $act player on $player ...");
	}
	exit 0;
}
if($mediator eq "stop"){
	if($player!~/\S/){
		printHead("Stop all playing songs ...");
		printCommandOutput("ps -ef|egrep 'playAt[A-Z][a-z]*\.sh|playsound\.sh'|grep -v grep|awk '{print \$2}'|xargs kill -9", "- stop all playing songs ...");
		printCommandOutput("rooftop:/home/pi/smarthome/killsound.sh", "- stop player processes on rooftop ...");
		printCommandOutput("factory:/home/pi/smarthome/killsound.sh", "- stop player processes on factory ...");
	} else{
		printHead("Stop song of player $player ...");
		$playerWord = "Middle";
		$playerWord = "Roof" if($player eq "rooftop");
		$playerWord = "Factory" if($player eq "factory");
		printCommandOutput("ps -ef|egrep 'playAt$playerWord\.sh|grep -v grep|awk '{print \$2}'|xargs kill -9", "- stop song of player $player ...");
		printCommandOutput("$player:/home/pi/smarthome/killsound.sh", "- stop song of player $player ...");
	}
	exit 0;
}
if($mediator eq "kill"){
	if($player!~/\S/){
		printHead("Kill all running players ...");
		printCommandOutput("ps -ef|egrep 'playAt[A-Z][a-z]*\.sh|playerSender\.sh|playsound\.sh'|grep -v grep|awk '{print \$2}'|xargs kill -9", "- stopping all player processes ...");
		printCommandOutput("rooftop:/home/pi/smarthome/killsound.sh", "- stopping player processes on rooftop ...");
		printCommandOutput("factory:/home/pi/smarthome/killsound.sh", "- stopping player processes on factory ...");
	} else{
		printHead("Kill player $player ...");
		$playerWord = "Middle";
		$playerWord = "Roof" if($player eq "rooftop");
		$playerWord = "Factory" if($player eq "factory");
		printCommandOutput("ps -ef|egrep 'playAt$playerWord\.sh|playerSender\.sh \-p $player'|grep -v grep|awk '{print \$2}'|xargs kill -9", "- killing player $player processes ...");
		printCommandOutput("$player:/home/pi/smarthome/killsound.sh", "- stopping player processes on $player ...");
	}
}
if($mediator eq "increase" or $mediator eq "decrease"){
	$Mediator = uc(substr($mediator, 0, 1)) . substr($mediator, 1);
	if($player!~/\S/){
		printHead("$Mediator volume all running players ...");
		printCommandOutput("rooftop:/home/pi/smarthome/audiocontrol.sh $mediator", "- $mediator volume on rooftop ...");
		printCommandOutput("factory:/home/pi/smarthome/audiocontrol.sh $mediator", "- $mediator volume on factory ...");
		printCommandOutput("smarthome:/home/pi/smarthome/audiocontrol.sh $mediator", "- $mediator volume on factory ...");
	} else{
		printHead("$Mediator volume of player $player ...");
		printCommandOutput("$player:/home/pi/smarthome/audiocontrol.sh $mediator", "- $mediator volume on $player ...");
	}
}
if($mediator eq "ajax"){ # 2nd argument: cmd
	my $host = "localhost";
	$cmd = urldecode($cmd);
	if($cmd=~/^([^\s:]+):(.+)$/){
		$host = $1;
		$cmd = $2;
		$cmd =~ s/^\s+//;
	}
	my $res = "";
	printlg("- ajax cmd: for host $host: $cmd");
	$res = `. /home/pi/.profile; $cmd 2>&1` if($host eq "localhost");
	$res = `ssh $host ". /home/pi/.profile; $cmd" 2>&1` if($host ne "localhost");
	chomp($res);
	printlg("	output of cmd ($cmd): $res");
	println($res);
	exit 0;
}
if($mediator eq "aplayer"){ # type: fix|record, sendto: rooftop|factory|middle, filename: <name-without-ext>, nr: <x>
	if($type eq "record"){
		$filename = uploadAudioFile($filename);
	}
	$soundfile = $middlefile;
	$soundfile = $rooffile if($sendto=~/roof/);
	$soundfile = $factfile if($sendto=~/fact/);
	system("$soundfile -f $filename");
	exit 0;
}
if($mediator eq "talk"){
	$mode = "prod";
	$mode = "test" if($mode=~/talktest/);
	my $ip = $ENV{REMOTE_ADDR};
	$client = "no";
	$client = "rooftop" if($ip eq "192.168.2.33");
	$client = "factory" if($ip eq "192.168.2.29");
	printlg("- remote addr: $ip, client: $client");
	$filename = uploadAudioFile($filename);
	$cmd = "$s2tfile $filename";
	printlg("- convert audio to text by: $cmd ...");
	$res = `$cmd`; chomp($res); $res = trim($res);
	$iserror = 0;
	$iserror = 1 if($res=~/ERROR:/);
	$text = $res;
	$text =~ s/^ERROR://;
	$text =~ s/^RESULT://;
	printlg("- utterance was: $text");
	# get current content of $resfile
	$newcontexe = ""; $newcontint = "";
	$oldcontexe = `cat $resfile`; chomp($oldcontexe);
	$oldcontexe =~ s/\d{6}:\s+//g;
	# put command into bubu
	$ts1res = getFileLM($resfile);
	$ts1int = getFileLM($intfile);
	if($mode eq "prod"){
		printlg("- exec: $wordtest \"talk$client $text\" ...");
		system("$wordtest \"talk$client $text\" >/dev/null 2>&1");
		$ts2res = getFileLM($resfile);
		$ts2int = getFileLM($intfile);
		$newcontexe = `cat $resfile`; chomp($newcontexe);
		$newcontint = `cat $intfile`; chomp($newcontint);
		$result = $newcontexe if($ts1res!=$ts2res);
		$result = $newcontint if($ts1int!=$ts2int);
		printlg("- result: $result");
		println($result);
	} else{
		println("what I understood: $text");
	}
	exit 0;
}
if($mediator eq "thumbnail"){
	$base = getBaseName($file);
	$tribe = getStemName($file);
	$dir = getDirName($file);
	$ext = lc(getFileExt($file));
	$typ = "image";
	$typ = "movie" if($ext eq "mp4" or $ext eq "mpg" or $ext eq "mpeg" or $ext eq "mov" or $ext eq "avi");
	$ext = "jpg" if($typ eq "movie");
	if(-f "$tdir/$tribe.$ext"){
		$tdir =~ s/^$sdir//;
		println("$tdir/$tribe.$ext");
	} else{
		print "none";
	}
	exit 0;
}
if($mediator eq "newdir"){
	system("mkdir $currdir/$newdir");
	exit 0;
}
if($mediator eq "youtube"){
	$url = urldecode($url);
	$currdir = urldecode($currdir);
	$bname = "youtube.$$";
	$tfile = "/home/pi/tmp/$bname.sh";
	open(T, ">$tfile") or die("ERROR: cannot write file $tfile!");
	print T "#!/usr/bin/perl\n cd $currdir\n touch $bname.txt\n /usr/bin/youtube \"$url\" $bname.mp3\n";
	close(T);
	printCommandAjax("nohup /bin/bash $tfile", "downloading from youtube ...");
	printFoot();
	exit 0;
}








#### bubu, only for old RPI





# if query_string is "lm", it returns only the last modified timestamp of control.htm
#if($q eq "lm"){
#	@info = stat($htmfile);
#	$lm = $info[9];
#	printlg("- print javascript code [top.informLastMod('$lm')] into output ...");
#	print "<html><head><title>Response</title><script language='javascript'>top.informLastMod('$lm');</script></head><body></body></html>\n";
#	exit 0;
#}

# if query_string is "mv", it returns the last song
#if($q eq "mv"){
#	$cont = `cat $movefile 2>/dev/null`; chomp($cont);
#	print "<html><head><title>Response</title><script language='javascript'>top.movePage(\"$cont\");</script></head><body></body></html>\n";
#	system(">$movefile");
#	exit 0;
#}

# if query_string is "ls", it returns the last song
#if($q eq "ls"){
#	$cont = `cat $lastfile 2>/dev/null`; chomp($cont);
#	print "<html><head><title>Response</title><script language='javascript'>top.readFile(\"$cont\");</script></head><body></body></html>\n";
#	exit 0;
#}

# if query_string is "er", it displays the last error message, if any
#if($q eq "er"){
#	$cont = `cat $errfile 2>/dev/null`; chomp($cont);
#	print "<html><head><title>Response</title><script language='javascript'>top.displayError(\"$cont\");</script></head><body></body></html>\n";
#	unlink($errfile) if(-f $errfile);
#	exit 0;
#}

#if($caller eq "intern"){
	# if query starts with ts=, the given time stamp is printed into $tsfile - to let the system know if it is still working
#	if($q=~/^ts=(.*)$/){
#		$timestamp = $1;
	#	printlg("- print $timestamp into $tsfile ...");
#		system("echo '$timestamp' >$tsfile");
#		exit 0;
#	}
#}



# if query contains action=getfiles, the given filename or directory files are returned in an array
if($action eq "getfiles"){
	use List::Util qw/shuffle/;
	printlg("- action: $action, entry: $entry ...");
	@files = ();
	if($entry=~/\.list$/){
		open(F, "<$entry") or die("ERROR: cannot read $entry: $!");
		while(<F>){
			$line = $_;
			chomp($line);
			$line =~ s/^\s*\d+\s*\)\s*//;
			push(@files, $line);
		}
		close(F);
		@files = shuffle(@files);
	} elsif(-f $entry){
		push(@files, $entry);
	} elsif(-e $entry){
		@files = shuffle(readDirectories($entry));
	}
	@newfiles = ();
	for($f=0;$f<$#files+1;$f++){
		$file = $files[$f];
		$file =~ s/\/home\/pi\/Music\/MIXES\/[^\/]+\//\/media\/disc\/Audio\//;
		$file =~ s/\/home\/pi\/Music\//\/media\/disc\/Audio\//;
		push(@newfiles, $file);
	}
	print "<html><head><title>Response</title><script language='javascript'>top.openInStage(new Array(\"". join("\",\"",@newfiles) ."\"));</script></head><body></body></html>\n";
	exit 0;
}


# if query_string starts with "output", it sends the file to a different output, e.g. rooftop or factory
if($action ne "output" and $q=~/^output=(.+)\b/){
	$handler = "";
	$handler = $rooffile if($output eq "rooftop");
	$handler = $factfile if($output eq "factory");
	$handler = $middlefile if($output eq "middle");
	my $file = $query->param("file");
	printlg("- exec: echo \"$now $handler -n 1 -f $file\" >$xsrvcmd ...");
	$now = `date +%H%M%S`; chomp($now);
	$res = `echo "$now $handler -n 1 -f $file" >$xsrvcmd`; chomp($res);
	$result = "$res";
	$resp = "OK";
	$resp = $result if($result=~/\S/);
	print "<html><head><title>Response</title><script language='javascript'>top.displayResponse(\"$resp\", '$out');</script></head><body></body></html>\n";
	exit 0;
}

# if query_string starts with "roofdirect", it sends the file to the rooftop
if($q=~/roofdirect=(.+)$/){
	$cmd = $1;
	if($cmd=~/(\d+),(.+)$/){
		$nr = $1;
		$cmd = $2;
	}
	printlg("- exec: echo \"$now $rooffile -n $nr -f $cmd\" >$xsrvcmd ...");
	$now = `date +%H%M%S`; chomp($now);
	$res = `echo "$now $rooffile -n $nr -f $cmd" >$xsrvcmd`; chomp($res);
	$result = "$res";
	$resp = "OK";
	$resp = $result if($result=~/\S/);
	print "<html><head><title>Response</title><script language='javascript'>top.displayResponse(\"$resp\", 'rooftop'); self.location.href='rooftop.htm';</script></head><body></body></html>\n";
	exit 0;
}

# if query_string is "roof", it sends the file to the rooftop
if($q eq "roof"){
	$CGI::POST_MAX = 1024 * 5000;
	my $query = new CGI;
	my $filename = $query->param("audio");
	$filename = "/var/upload/$filename";
	my $fh = $query->upload("audio");
	my $result = ""; my $text = "";
	printlg("- write binary file $filename ...");
	if(open(U, ">$filename" )){
		binmode U;
		while(<$fh>){
			print U;
		}
		close U;
	} else{
 		$result = "ERROR: cannot write binary wav file $filename: $!";
		printlg($result);
	}
	$now = `date +%H%M%S`; chomp($now);
	printlg("- exec: echo \"$now $rooffile -f $filename\" >$xsrvcmd ...");
	$res = `echo "$now $rooffile -f $filename" >$xsrvcmd`; chomp($res);
	$result = "$res";
	$resp = "OK";
	$resp = $result if($result=~/\S/);
	print "<html><head><title>Response</title><script language='javascript'>top.displayResponse(\"$resp\", 'rooftop');</script></head><body></body></html>\n";
	exit 0;
}

# if query_string is "fact", it sends the file to the factory
if($q eq "fact"){
	$CGI::POST_MAX = 1024 * 5000;
	my $query = new CGI;
	my $filename = $query->param("audio");
	$filename = "/var/upload/$filename";
	my $fh = $query->upload("audio");
	my $result = ""; my $text = "";
	printlg("- write binary file $filename ...");
	if(open(U, ">$filename" )){
		binmode U;
		while(<$fh>){
			print U;
		}
		close U;
	} else{
 		$result = "ERROR: cannot write binary wav file $filename: $!";
		printlg($result);
	}
	$now = `date +%H%M%S`; chomp($now);
	printlg("- exec: echo \"$now $factfile -f $filename\" >$xsrvcmd ...");
	$res = `echo "$now $factfile -f $filename" >$xsrvcmd`; chomp($res);
	$result = "$res";
	$resp = "OK";
	$resp = $result if($result=~/\S/);
	print "<html><head><title>Response</title><script language='javascript'>top.displayResponse(\"$resp\", 'factory');</script></head><body></body></html>\n";
	exit 0;
}

# if query_string is "middle", it sends the file to the middle
if($q eq "middle"){
	$CGI::POST_MAX = 1024 * 5000;
	my $query = new CGI;
	my $filename = $query->param("audio");
	$filename = "/var/upload/$filename";
	my $fh = $query->upload("audio");
	my $result = ""; my $text = "";
	printlg("- write binary file $filename ...");
	if(open(U, ">$filename" )){
		binmode U;
		while(<$fh>){
			print U;
		}
		close U;
	} else{
 		$result = "ERROR: cannot write binary wav file $filename: $!";
		printlg($result);
	}
	$now = `date +%H%M%S`; chomp($now);
	printlg("- exec: echo \"$now $middlefile -f $filename\" >$xsrvcmd ...");
	$res = `echo "$now $middlefile -f $filename" >$xsrvcmd`; chomp($res);
	$result = "$res";
	$resp = "OK";
	$resp = $result if($result=~/\S/);
	print "<html><head><title>Response</title><script language='javascript'>top.displayResponse(\"$resp\", 'middle');</script></head><body></body></html>\n";
	exit 0;
}

# if query_string is "talk", it sends the file to IBM, and waits for the result to display in return
if($q=~/talk/){
	$mode = "prod";
	$mode = "test" if($q=~/talktest/);
	my $ip = $ENV{REMOTE_ADDR};
	$client = "no";
	$client = "rooftop" if($ip eq "192.168.2.33");
	$client = "factory" if($ip eq "192.168.2.29");
	printlg("- remote addr: $ip, client: $client");
	$CGI::POST_MAX = 1024 * 5000;
	my $query = new CGI;
	my $filename = $query->param("audio");
	$filename = "/var/upload/$filename";
	my $fh = $query->upload("audio");
	my $result = ""; my $text = ""; my $resp = "";
	printlg("- write binary file $filename ...");
	if(open(U, ">$filename" )){
		binmode U;
		while(<$fh>){
			print U;
		}
		close U;
		$cmd = "$s2tfile $filename";
		printlg("- convert audio to text by: $cmd ...");
		$res = `$cmd`; chomp($res);
		if($res=~/^ERROR:/){
			$result = $res;
		} else{
			$res =~ s/^RESULT:\s+//;
			$text = $res;
			if($text=~/\S/){
				printlg("- utterance was: $text");
				$result = "what I understood: $text";
				# get current content of $resfile
				$newcontexe = ""; $newcontint = "";
				$oldcontexe = `cat $resfile`; chomp($oldcontexe);
				$oldcontexe =~ s/\d{6}:\s+//g;
				# put command into bubu
				$ts1res = getFileLM($resfile);
				$ts1int = getFileLM($intfile);
				if($mode eq "prod"){
					printlg("- exec: $wordtest \"talk$client $text\" ...");
					system("$wordtest \"talk$client $text\" >/dev/null 2>&1");
					$ts2res = getFileLM($resfile);
					$ts2int = getFileLM($intfile);
					$newcontexe = `cat $resfile`; chomp($newcontexe);
					$newcontint = `cat $intfile`; chomp($newcontint);
					$result = $newcontexe if($ts1res!=$ts2res);
					$result = $newcontint if($ts1int!=$ts2int);
				}
			} else{
				$result = "ERROR: could.not.understand";
			}
		}
	} else{
 		$result = "ERROR: cannot write binary wav file $filename: $!";
	}
	$rc = 0;
	$rc = 1 if($result=~/ERROR/);
	$result =~ s/^ERROR:\s+//;
	print $result;
	printlg($result);
	exit $rc;
}

# if query starts with sh=, it's a command for smarthome
#if($q=~/^sh=(.*)$/){
#	$cmd = $1;
#	if($cmd=~/foto_/ or $cmd=~/pumpe_schacht/){
#		$filter = "Slurry";
#		$filter = "Stock" if($cmd=~/vorrat/);
#		@files = dirFilterPos($filter, readDirectory($photodir));
#		$lastfile = $files[-1];
#	}
#	$arg = "";
#	if($cmd=~/fenster_/){
#		$cmd =~ s/:[\d\.]+$//;
#		printlg("- going to execute the command: $exfile -c \"$cmd\"");
#		$res = `$exfile -c "$cmd" 2>&1|grep -i "The state of fenster_[a-z][a-z][a-z]* is:"|sed -n '1p'|sed -e 's%^[0-9][0-9]* *%%'`;
#		chomp($res);
#		$arg = "'RESPONSE: $res'";
#	} elsif($cmd=~/display/){
#		$cmd =~ s/:[\d\.]+$//;
#		printlg("- going to execute the command: $bufile");
#		system("$bufile >/dev/null 2>&1");
#	} else{
#		printlg("- going to execute the command: $infile \"$cmd\"");
#		system("$infile \"$cmd\" >/dev/null 2>&1");
#	}
#	if($cmd=~/pumpe_schacht/){
#		$gap = 10;
#		$gap = $1 if($cmd=~/\.(\d+)$/);
#		printlg("- going to wait for $gap seconds before checking for a photo ...");
#		sleep $gap;
#	}
#	if($cmd=~/foto_/ or $cmd=~/pumpe_schacht/){
#		$rounds = 22; $gap = 3; $found=0; $nr=0;
#		while(!$found and $nr<$rounds){
#			$nr++;
#			sleep($gap);
#			@files = dirFilterPos($filter, readDirectory($photodir));
#			$newestfile = $files[-1];
#			$found = 1 if($newestfile ne $lastfile);
#		}
#		$arg = "'ERROR: could not take a photo!'";
#		$arg = "'$newestfile'" if($found);
#		printlg("	- after $nr rounds, a photo could be found: $found (argument for javascript client routine top.informAboutSent: $arg)");
#	}
#	print "<html><head><title>Response</title><script language='javascript'>top.informAboutSent($arg);</script></head><body bgcolor='white'>";
#	print "</body></html>\n";
#	exit 0;
#}

# if query starts with gl=, the given list file is returned
#if($q=~/gl=(.*)$/){
#	$listfile = $1;
#	printlg("- query: $q, listfile: $listfile");
#	if($listfile!~/\S/){ # first run ends here - after page is loaded, this function is called again (if Browse: is a list file)
#		printlg("	- empty, so we just return 200 and exit 0");
#		exit 0;
#	}
#	$cont = "";
#	open(I, '<:encoding(UTF-8)', $listfile);
#	while(<I>){ chomp($_); $cont .= $_ ."\n"; } close(I);
#	$cont = `cat $listfile 2>/dev/null`; chomp($cont);
#	$cont =~ s/\r?\n/%!NL!%/gs; $cont =~ s/\r?\n/%!NL!%/gs;
#	$cont =~ s/\"/%!QT!%/gs; $cont =~ s/\"/%!QT!%/gs;
#	printlg("- now we display the content of listfile $listfile ...");
#	printlg("	- cont: $cont");
#	print "<html><head><meta charset='UTF-8'/><title>Response</title><script language='javascript'>top.updateListContent(\"$cont\");</script></head><body></body></html>\n";
#	exit 0;
#}


printlg("ERROR: could not find anything to do with the query: $q");


exit 0;


printHead();
println("<div>Query: $q</div><ul>");
$output = "hdmi";
@pairs = split(/\&/, $q);
for($p=0;$p<$#pairs+1;$p++){
	($key, $val) = split(/=/, $pairs[$p]);
	if($key=~/^control(.)?$/){
		$c = uc($1);
		$output = "factory" if($c eq "F");
		$output = "rooftop" if($c eq "R");
		$output = "main" if($c eq "M");
		$key = "control";
	}
	if($key=~/^entry(.)?$/){
		$c = uc($1);
		$output = "factory" if($c eq "F");
		$output = "rooftop" if($c eq "R");
		$output = "main" if($c eq "M");
		$key = "entry";
	}
	printli("$key: $val");
	$$key = $val;
}
$cmd = "";
$action = $defaction if($action!~/\S/);
if($action eq "control" and $entry eq "next"){
	$action = "remote";
	$entry = "next";
}
if($action eq "control"){
	if($entry eq "stop"){
		printli("	- entry was given: $entry");
		printli("		- kill all players ...");
		printli("	- restart $xsrvsh ...");
		system("$xsrvsh restart");
		system("ps -ef|grep \"omxplayer|vlc|PictureFrame|gpicview\"|grep -v grep|awk '{print \$2}'|xargs kill -9");
		printli("		- exec: ssh rooftop \"$hdir/killsound.sh\" ...");
		system("ssh rooftop \"$hdir/killsound.sh\"");
		printli("		- exec: ssh factory \"$hdir/killsound.sh\" ...");
		system("ssh factory \"$hdir/killsound.sh\"");
		print "<html><head><title>Response</title><script language='javascript'>top.informAboutSent('OK');</script></head><body bgcolor='white'>";
		print "</body></html>\n";
		exit 0;
	}
	elsif($entry=~/\S/){
		printli("	- entry was given: $entry");
		$cmd = "$control $output to $entry";
	} elsif($category=~/\S/){ # only if user clicks at category at the top
		$category = lc($category);
		printli("	- category was given: $category");
		$dir = $dirs{$category};
		$dir = $listfile if($category eq "list");
		$dir = $tvlist if($category eq "tv");
		$dir = $newslist if($category eq "news");
		$dir = $youtubelist if($category eq "youtube");
		$cmd = "$control $output $dir";
	} elsif($favorite=~/\S/){ # only if user clicks at favorite at the top
		$favorite = lc($favorite);
		printli("	- favorite was given: $favorite");
		$dir = $dirs{"video"} ."/Favorites/$favorite";
		$cmd = "$control $output $dir";
	}
}
elsif($action eq "play"){
	if($entry=~/\S/){
		printli("	- entry was given: $entry");
		$cmd = "$control $output play $entry";
	}
}
elsif($action eq "up" or $action eq "next"){
	$cmd = "$control $output $action";
}
elsif($action eq "remote"){
	$cmd = "$remote $entry";
}
if($cmd=~/\S/){
	printli("exec: $cmd ...");
	$res = `$cmd`;
	chomp($res);
	$res =~ s/\r?\n/\n<br\/>/g;
	printli("result:\n<br/>$res");
} else{
	printli("ERROR: could not identify a command!");
}

println("</ul>");
printFoot();
close(L) if($openedlogfile);



sub getMediaDuration{
	my $file = shift;
	my $tribe = getStemName($file);
	my $dir = getDirName($file);
	my $ext = lc(getFileExt($file));
	my $durfile = "$dir/$tribe.dur";
	printlg("- search duration of file $file, $durfile ...");
	my $dur = 0;
	if(-f $durfile){
		$dur = `cat $durfile`;
		chomp($dur);
		$dur =~ s/,+\s*$//;
		$dur = time2sec($dur);
		printlg("- $durfile contains: $dur");
	}
	elsif($ext ne "mp3"){
		$dur = `ffmpeg -i $file 2>&1|grep -i duration:|awk '{print \$2}'`; # e.g.: 01:48:03.03, (with comma!)
		chomp($dur);
		$dur =~ s/,+\s*$//;
		$dur = time2sec($dur);
		printlg("- no $durfile, but it's NOT mp3. duration: $dur");
	} else{
		$dur = `mp3info -p %S $file`;
		chomp($dur);
		printlg("- no $durfile, but it's mp3. duration: $dur");
	}
	return $dur;
}
sub getAudioLibrary{ # for mp4 files: the audio part is at the bottom
	my $file = shift;
	my $alib = `mediainfo $file|grep -i "writing library"|sed -n '\$p'|awk '{print \$4}'|tr "[A-Z]" "[a-z]"`; # Constant or Variable
	chomp($alib);
	return $alib;
}
sub getAudioRate{ # for mp4 files: the audio part is at the bottom
	my $file = shift;
	my $rmode = `mediainfo $file|grep "Bit rate mode"|sed -n '\$p'|awk '{print \$5}'`; # Constant or Variable
	chomp($rmode);
	my $rrate = "variable";
	$rrate = `mediainfo $file|grep "Bit rate"|grep -v "Bit rate mode"|sed -n '\$p'|awk '{print \$4}'` if($rmode eq "Constant");
	return $rrate;
}
sub calculateMediaPositions{
	my $txtfile = shift;
	my $totalDur = shift;
	my @lines = @_;
	my @positions = (); my @names = (); my @poslines = ();
	$totalDur =~ s/\.\d+$//;
	$totalDur = sec2time($totalDur) if($totalDur!~/:/);
	my $hour = 0; my $lastmin = 0;
	for(my $i=0;$i<$#lines+1;$i++){
		my $line = trim($lines[$i]);
		if($line=~/^(\d\d:\d\d)\s+(\D.+)$/){
			$line = $1 ." 00:00 ". $2;
		}
		if($line=~/^(\d\d):(\d\d)\s+(\d\d:\d\d)\s+(\S.+)$/){
			my $min = int($1);
			my $sec = int($2);
			my $dur = $3;
			my $name = $4;
			$hour++ if($min<$lastmin);
			$lastmin = $min;
			my $pos = d2($hour) .":". d2($min) .":". d2($sec);
			push(@positions, $pos);
			push(@names, $name);
		}
	}
	push(@positions, $totalDur);
	open(T, ">$txtfile") or die("ERROR: cannot write $txtfile: $!");
	for($i=0;$i<$#names+1;$i++){
		my $name = trim($names[$i]);
		my $pos = $positions[$i];
		my $till = $positions[$i+1];
		my $dursec = int(time2sec($till) - time2sec($pos));
		if($dursec<0){
			$positions[$i+1] = sec2time(int(time2sec($pos)) + 1);
			$till = $positions[$i+1];
			$dursec = int(time2sec($till) - time2sec($pos));
		}
		my $dur = sec2time($dursec);
		$pos =~ s/^\d\d://;
		$dur =~ s/^\d\d://;
		push(@poslines, "$pos $dur $name");
		print T "$pos $dur $name\n";
	}
	close(T);
	return join("\n", @poslines);
}
sub sqliteQuery{
	my $q = shift;
	$q = trim($q);
#printlg("- sqlite3 query: $q");
	my $isselect = 0;
	$isselect = 1 if($q=~/^select\b/i);
	system("/usr/bin/sqlite3 $sqldbfile \"$q\" >$tmpfile2");
	return if(!$isselect);
	my @lines = getLinesOfFile($tmpfile2);
	my @result = ();
	my @changes = ();
		for(my $i=1;$i<$#lines+1;$i++){
				my $line = $lines[$i]; # 2nd line is: ----------  ----------------------------------------------------------------------------------------------------
				if($i==1){
						my $lastchar = "";
						for(my $c=0;$c<length($line);$c++){
								my $char = substr($line, $c, 1);
								push(@changes, $c) if($char ne $lastchar);
								$lastchar = $char;
						}
						push(@changes, length($line));
						next;
				}
				my @fields = ();
				for(my $c=0;$c<$#changes+1;$c+=2){
						my $p = $changes[$c];
						my $q = $changes[$c+1];
						push(@fields, substr($line, $p, ($q-$p)));
				}
		push(@result, [@fields]);
	}
	return @result;
}
sub printlg{
	my $msg = shift;
	my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
	$hour = d2($hour);
	$min = d2($min);
	$sec = d2($sec);
	print L "$hour$min$sec ". $msg ."\n" if($openedlogfile);
}
sub printP{
	my $msg = shift;
	println("\n<br/>". $msg);
}
sub println{
	my $msg = shift;
	print $msg ."\n";
	printlg($msg);
}
sub printli{
	my $msg = shift;
	println("<li>$msg</li>");
}
sub d2{
	my $nr = shift;
	return "0$nr" if($nr<10);
	return $nr;
}

sub printJavascript{
	my $cmd = shift;
	println("<script language='javascript'>$cmd</script>");
}

sub printRedirect{
	my $url = shift;
	my $timeout = shift;
	$timeout = 0 if($timeout!~/\S/);
	$timeout = $redirectDefault if($timeout=~/\D/);
	println("<script language='javascript'>window.setTimeout(\"document.location.href='$url'\", $timeout);</script>");
}

sub printLink{
	my $main = shift;
	my $sub = shift;
	println("<script language='javascript'>try{parent.openLink('$main', '$sub');}catch(ex){}</script>");
}

sub printFocus{
	my $main = shift;
	my $sub = shift;
	println("<script language='javascript'>try{parent.focusType('$main'); parent.focusSub('$main', '$sub');}catch(ex){}</script>");
}

sub printAction{
	my $main = shift;
	my $sub = shift;
	println("<script language='javascript'>try{parent.openMenu('$main'); parent.startAction('$main', '$sub');}catch(ex){}</script>");
}

my $printTable = 0;
sub printHead{
	my $arg1 = shift; # title - if not given, the global variable is taken
	my $arg2 = shift; # whether the content should be printed into a table in order to have some distance to the frame, default: no. But: if $arg1 is set, the default is yes
	my $arg3 = shift; # whether to print a <pre> at the end: the default is yes: if not wanted, set it to no
	my $mytitle = $title;
	$mytitle = $arg1 if($arg1=~/\S/);
	$printTable = "no";
	$printTable = "yes" if($arg1=~/\S/);
	$printTable = $arg2 if($arg2=~/\S/);
	$printTable = $printTable eq "yes" ? 1 : 0;
	my $nowts = time;
	println('<html>');
	println('<head><meta charset="UTF-8"/>');
	println("<link rel='stylesheet' href='/styles.css?$nowts'/>");
	println("<link rel='icon' type='image/vnd.microsoft.icon' href='/favicon.ico'/>");
	println("<script language='javascript' src='/script.js?$nowts'></script>");
	println("<script language='javascript'>document.addEventListener('dblclick', goHome); function goHome(){ parent.goHome(); }</script>");
	println("<title>$mytitle</title>");
	println('</head>');
	println('<body>');
	println("<table width='100%' height='100%' cellpadding='0' cellspacing='0' border='0'><tr><td width='100%' height='40' colspan='2'>&nbsp;</td></tr><tr><td width='20'>&nbsp;</td><td valign='top' width='*' height='*'>") if($printTable);
	println("<h2>$mytitle</h2>");
	println("<pre>") if($arg3 ne "no");
}

sub checkSpecialPassword{
	my $password = shift;
	my $err = 0;
	$err = 1 if(! -f $passfile);
	my $pass = `cat $passfile 2>/dev/null`;
	chomp($pass);
	chomp($password);
	$err = 1 if($password ne $pass);
	if($err){
		printHead("Authorization needed");
		println("ERROR: wrong password!");
#		println("ERROR: wrong password (given: |$password|, needed: |$pass|)!");
		return 0;
	}
	return 1;
}

sub getCommand{
	my $cmd = shift;
	my $host = "localhost";
	if($cmd=~/^([^\s:]+):(.+)$/){
		$host = $1;
		$cmd = $2;
		$cmd =~ s/^\s+//;
	}	
	my $res = "";
	$res = `$cmd 2>&1` if($host eq "localhost");
	$res = `ssh $host "$cmd" 2>&1` if($host ne "localhost");
	chomp($res);
	return $res;
}

sub getFileSize{
	my $fpath = shift;
	my $mode = shift; # human entails ls -alh ...!
	my $flag = "al";
	$flag = "alh" if($mode eq "human");
	my $host = "localhost";
	if($fpath=~/^([^\s:]+):(.+)$/){
		$host = $1;
		$fpath = $2;
		$fpath =~ s/^\s+//;
	}	
	if($host eq "localhost"){
		my $size = (stat($fpath))[7];
		if($size > 1099511627776){  #   TiB: 1024 GiB
			return sprintf("%.2fTB", $size / 1099511627776);
		}
		elsif($size > 1073741824){  #   GiB: 1024 MiB
			return sprintf("%.2fGB", $size / 1073741824);
		}
		elsif($size > 1048576){	 #   MiB: 1024 KiB
			return sprintf("%.2fMB", $size / 1048576);
		}
		elsif($size > 1024){		#   KiB: 1024 B
			return sprintf("%.2fKB", $size / 1024);
		}
		else{						#   bytes
			return "${size}B";
		}
	}
	system("ssh $host \"ls -$flag $fpath 2>&1\" >$tmpfile 2>&1") if($host ne "localhost");
	my $fline = `cat $tmpfile`;
	chomp($fline);
	my @elems = split(/\s+/, $fline);
	$elems[4] =~ s/,/\./;
	return $elems[4];
}

sub toEntities{
	my $str = shift;
	$str =~ s/ä/&auml;/g;
	$str =~ s/Ä/&Auml;/g;
	$str =~ s/ü/&uuml;/g;
	$str =~ s/Ü/&Uuml;/g;
	$str =~ s/ö/&ouml;/g;
	$str =~ s/Ö/&Ouml;/g;
	$str =~ s/ß/&szlig;/g;
	return $str;
}

sub printSystemCommand{
	my $caption = shift;
	my $cmd = shift;
	my $host = "localhost";
	if($cmd=~/^([^\s:]+):(.+)$/){
		$host = $1;
		$cmd = $2;
		$cmd =~ s/^\s+//;
	}
	println("<h3>$caption</h3>");
	println("<pre>");
	system("$cmd 2>&1") if($host eq "localhost");
	system("ssh $host \"$cmd 2>&1\" 2>&1") if($host ne "localhost");
	println("</pre>");
}

sub getCommandOutput{
	my $cmd = shift;
	my $info = shift;
	my $redir = shift; # tmp ($tmpfile) or null (/dev/null)
	my $mode = "fg";
	if($info=~/^([fb]g)/){
		$mode = $1;
		$info =~ s/^[fb]g:?//;
	}
	my $cmdadd = "";
	$cmdadd = " &" if($mode eq "bg");
	$redir = "tmp" if($redir ne "null");
	$redir = ($redir eq "tmp" ? $tmpfile : "/dev/null");
	$info = "- exec: $cmd ..." if($info!~/\S/);
	println($info);
	my @lines = ();
	my $host = "localhost";
	if($cmd=~/^([^\s:]+):(.+)$/){
		$host = $1;
		$cmd = $2;
		$cmd =~ s/^\s+//;
	}	
	system("$cmd >$redir 2>&1$cmdadd") if($host eq "localhost");
	system("ssh $host \"$cmd 2>&1$cmdadd\" >$redir 2>&1") if($host ne "localhost");
	return () if($redir ne $tmpfile);
	open(F, "<$tmpfile") or die("ERROR: cannot read $tmpfile: $!");
	while(<F>){
		chomp($_);
		$line = $_;
		push(@lines, $line);
	}
	close(F);
	return @lines;
}

sub printCommandAjax{ # these created functions are called at the end - so you need to call printFoot()!
	my $cmd = shift;
	my $info = shift;
	my $printcap = 0;
	if($info=~/^cap:/){
		$printcap = 1;
		$info =~ s/^cap://;
	}
	$info = "- exec: $cmd ..." if($info!~/\S/);
	my $elemId = time;
	$elemId .= int(rand(10000));
	$printcap==1 ? println("<h3>$info</h3>") : println($info);
	println("<img src='/images/sandglass.gif' alt='waiting ...' title='waiting ...' height='80' id='wait$elemId' border='0'/><pre id='pre$elemId'></pre>");
	println("<script language='javascript'>");
	println("function ajax$elemId(){");
	println("var xmlhttp$elemId = new XMLHttpRequest();");
	println("var pre$elemId = document.getElementById('pre$elemId');");
	println("var wait$elemId = document.getElementById('wait$elemId');");
	println("xmlhttp$elemId.onreadystatechange = function(){ try{");
	println("	if(xmlhttp$elemId.readyState==4){");
	println("		wait$elemId.style.display='none';");
	println("		if(xmlhttp$elemId.status>=200 && xmlhttp$elemId.status<300){");
	println("			var t = xmlhttp$elemId.responseText.replace(/\s+\$/g, '');");
	println("			pre$elemId.innerHTML = t;");
	println("			try{parent.returnAjax('success', \"$cmd\", \"$t\");}catch(ex){};");
	println("		}");
	println("		else{");
	println("			var t = 'ERROR: '+ xmlhttp$elemId.statusText;");
	println("			pre$elemId.innerText = t;");
	println("			try{parent.returnAjax('error', \"$cmd\", \"$t\");}catch(ex){};");
	println("		}");
	println("	}");
	println("} catch(ex){");
	println("console.log(ex);");
	println("}}");
	println("xmlhttp$elemId.open('GET', '/cgi-bin/bubu?mediator=ajax&cmd='+ encodeURIComponent(\"$cmd\"));");
	println("xmlhttp$elemId.send();");
	println("}");
	println("</script>");
	push(@ajaxfunctions, "ajax$elemId");
}

sub printCommandOutput{
	my $cmd = shift;
	my $info = shift;
	my $printcap = 0;
	if($info=~/^cap:/){
		$printcap = 1;
		$info =~ s/^cap://;
	}
	my $mode = shift; # if "return" is given, the output is not printed, but returned
	$mode = "print" if($mode!~/\S/ or $mode eq "print");
	my $arg4 = shift;
	my $printReturn = 0;
	$printReturn = 1 if($arg4==1);
	$info = "- exec: $cmd ..." if($info!~/\S/);
	my $hasError = 0;
	my $host = "localhost";
	my @lines = ();
	if($cmd=~/^([^\s:]+):(.+)$/){
		$host = $1;
		$cmd = $2;
		$cmd =~ s/^\s+//;
	}	
	if($mode eq "print"){
		$printcap==1 ? println("<h3>$info</h3>") : println($info);
		println("<pre>");
	}
	system("$cmd >$tmpfile 2>&1") if($host eq "localhost");
	system("ssh $host \"$cmd 2>&1\" >$tmpfile 2>&1") if($host ne "localhost");
	open(F, "<$tmpfile") or die("ERROR: cannot read $tmpfile: $!");
	while(<F>){
		chomp($_);
		println($_) if($mode eq "print");
		push(@lines, $_) if($mode eq "return");
		$hasError = 1 if($_=~/ERROR/);
	}
	close(F);
	println("</pre>") if($mode eq "print");
	println("<script language='javascript'>history.back();</script>") if($mode eq "print" and $printReturn);
	return ($mode eq "print" ? $hasError : join("\n", @lines));
}

sub printWgetOutput{
	my $url = shift;
	system("wget --no-check-certificate -O $tmpfile \"$url\"");
	open(F, "<$tmpfile") or die("ERROR: cannot read $tmpfile: $!");
	my $iserr = 0;
	while(<F>){
		chomp($_);
		my $line = $_;
		$line =~ s/<br\s*\/>//g;
		chomp($line);
		$line =~ s/\s\s+/ /g;
		$iserr = 1 if($line=~/ERROR/ or $line==~/could not resolve/i);
		println($line);
	}
	close(F);
	return $iserr;
}

sub printFoot{
	println("</td></tr></table>") if($printTable);
	println("</pre><script language='javascript'> function ajaxCallStack(){");
	for(my $f=0;$f<$#ajaxfunctions+1;$f++){
		println($ajaxfunctions[$f] ."();");
	}
	println("} window.onload = ajaxCallStack; parent.notifyAboutContentLoaded(); </script></body>");
	println("</html>");
	exit 0;
}

sub postIntoFile{
	my $maxsize = shift;
	my $filedata = shift;
	my $uploadfile = shift;
	$CGI::POST_MAX = $maxsize;
	my $query = new CGI;
	$filedata = $query->param($filedata);
	my $isError = 0;
	if(open U, ">:encoding(utf-8)", $uploadfile){
#	if(open(U, ">$uploadfile")){
		binmode(U, ":utf8");
#		binmode U;
		print U $filedata;
		close U;
		println("<pre>");
		my @lines = getCommandOutput("dos2unix $uploadfile");
		my $output = join("\n", @lines);
		println($output);
		println("</pre>");
		$isError = "ERROR: $output" if($output=~/error/i);
	} else{
		$isError = "ERROR: cannot write binary uploadfile $uploadfile: $!";
	}
	return $isError ? $isError : $uploadfile;
}

sub uploadAudioFile{
	$CGI::POST_MAX = 1024 * 5000;
	my $query = new CGI;
	my $filename = $query->param("audio");
	$filename = "/var/upload/$filename";
	my $fh = $query->upload("audio");
	my $result = ""; my $text = "";
	printlg("- write binary file $filename ...");
	if(open(U, ">$filename" )){
		binmode U;
		while(<$fh>){
			print U;
		}
		close U;
		my $filetribe = getStemName($filename);
		my $filenew = "/media/disc/Audio/Smarthome/SoundUploads/$filetribe.mp3";
		system("ffmpeg -y -i $filename -vn -b:a 192k $filenew");
		printlg("- converted $filename to $filenew");
		return $filenew;
	} else{
 		$result = "ERROR: cannot write binary wav file $filename: $!";
		printlg($result);
	}
}

sub uploadFile{
	my $maxsize = shift;
	my $fileargument = shift;
	my $uploaddir = shift;
	$uploaddir = $uploaddirtmp if($uploaddir!~/\S/);
	my $uploaded = 0;
	my $newname = shift; # e.g. %BASE%.20201115.kdbx
	my $argupload = shift;
	$uploaded = 1 if($newname eq "uploaded" or $argupload eq "uploaded");
	$CGI::POST_MAX = $maxsize;
	my $query = new CGI if($query!=0);
printlg("- fileargument: $fileargument");
	my $filename = $query->param($fileargument);
printlg("- filename: $filename");
	$filename =~ s/^.*[\\\/]([^\\\/]+)$/$1/;
	$filename =~ s/\s+/_/g;
	$filename =~ s/[^\w_\-\.\d]//g;
	$filenew = $filename;
	if($newname=~/\S/){
		$filenew = $newname;
		$filenew =~ s/%BASE%/&getStemName($filename)/ge;
		$filenew =~ s/%EXT%/&getFileExt($filename)/ge;
	}
	return $filenew if($uploaded);
	my $fh = $query->upload($fileargument);
	my $isError = 0;
	unlink("$uploaddirtmp/$filename") if(-f "$uploaddirtmp/$filename");
printlg("- going to write uploaded file $filename ...");
	if(open(U, ">$uploaddirtmp/$filename")){
#		binmode U;
		while(<$fh>){
			print U $_;
		}
		close U;
		close $fh;
		$cmdmove = "";
$fs1 = getFileSize("$uploaddirtmp/$filename");
printlg("- size of uploaded file: $fs1");
printlg("- ok, moving temp file ...");
		$cmdmove = "mv $uploaddirtmp/$filename $uploaddir/$filenew" if($uploaddir ne $uploaddirtmp or $filename ne $filenew);
printlg("- cmd: $cmdmove");
		if($cmdmove ne ""){
printlg("- performing command and collecting output ...");
			my @lines = getCommandOutput($cmdmove);
$fs2 = getFileSize("$uploaddir/$filenew");
printlg("- size of moved file: $fs2");
			my $output = join("\n", @lines);
			$isError = "ERROR: $output" if($output=~/\S/);
		}
	} else{
		$isError = "ERROR: cannot write binary uploadfile $uploaddirtmp/$filename: $!";
	}
	return $isError ? $isError : $filenew;
}

sub printToFile{
	my $file = shift;
	my $code = shift;
	open TOFILE, ">:encoding(utf-8)", $file or return "ERROR: $!";
#	open(TOFILE, ">$file") or return "ERROR: $!";
	print TOFILE $code;
	close(TOFILE);
	return 0;
}

sub getLinesOfFile{
	my $filename = shift;
	my $onlyNonEmpty = shift;
	$onlyNonEmpty = 0 if($onlyNonEmpty!~/\S/);
	my @lines = ();
	use utf8::all;
	open F, "<:encoding(utf-8)", $filename or die("ERROR: cannot read file $filename: $!");
#	open(F, "<$filename") or die("ERROR: cannot read $filename: $!");
	while(<F>){
		chomp($_);
		push(@lines, $_) if(!$onlyNonEmpty or $_=~/\S/);
	}
	close(F);
	return @lines;
}

sub getLastLineOfFile{
	my $filename = shift;
	my $onlyNonEmpty = shift;
	$onlyNonEmpty = 1 if($onlyNonEmpty!~/\S/);
	my $res = "";
	use utf8::all;
	open F, "<:encoding(utf-8)", $filename or die("ERROR: cannot read file $filename: $!");
#	open(F, "<$filename") or return "ERROR: cannot read $filename: $!";
	while(<F>){
		chomp($_);
		$res = $_ if(!$onlyNonEmpty or $_=~/\S/);
	}
	close(F);
	return $res;
}

sub getFirstLineOfFile{
	my $filename = shift;
	my $onlyNonEmpty = shift;
	$onlyNonEmpty = 1 if($onlyNonEmpty!~/\S/);
	my $res = "";
	my $lnr = 0;
	use utf8::all;
	open F, "<:encoding(utf-8)", $filename or die("ERROR: cannot read file $filename: $!");
#	open(F, "<$filename") or return "ERROR: cannot read $filename: $!";
	while(<F>){
		chomp($_);
		$lnr++ if(!$onlyNonEmpty or $_=~/\S/);
		if($lnr==1){
			$res = $_;
			last;
		}
	}
	close(F);
	return $res;
}

sub getLibrarySetting{
	my $var = shift;
	my $val = `grep $var= $hdir/library.sh`;
	chomp($val);
	$val = $1 if($val=~/^.+=\"([^\"]+)\"/);
	return $val;
}

# read directory without . and ..
sub readDirectory{
	my $dir = shift;
	my @files = ();
	my @allfiles = ();
	printAndDie("Directory $dir not found: $!") if(!-e $dir);
	opendir(D, $dir);
	@allfiles = readdir(D);
	closedir(D);
	foreach my $entry(@allfiles){
		next if($entry eq "." or $entry eq "..");
		my $target = resolveLink("$dir/$entry");
		if($target){ $entry = $target; }
		push(@files, $entry);
	}
	return sort @files;
}
# read a directory recursively
sub readDirectories{
	my $dir = shift;
	my $arrref = shift;
	@readdirectories_files = () if($arrref==0);
	@readdirectories_files = @{$arrref} if($arrref!=0);
	opendir(DIR, $dir) || die "$dir: $!";
	my @list = readdir(DIR);
	closedir(DIR);
	foreach my $entry(@list){
		next if($entry eq "." or $entry eq "..");
		my $target = resolveLink("$dir/$entry");
		if($target){ $entry = $target; }
		else{ $entry = $dir ."/". $entry; }
		(!-d $entry) ? push(@readdirectories_files, $entry) : readDirectories($entry, \@readdirectories_files);
	}
	return @readdirectories_files;
}
sub dirFilterPos{
	my $filter = shift;
	my @entries = @_;
	my @newlist;
	my @negexts = split(/,\s*/, $filter);
	foreach my $entry(@entries){
		my $ok = 0;
		$ok = 1 if($entry=~/$filter/);
		next if(!$ok);
		push(@newlist, $entry);
	}
	return @newlist;
}
# get the directory name of a file path
sub getDirName{
# returns directory name of file path
# arguments: file path
# calls: none
# returns: directory name of file path
# example: getDirName("$ACTISEDI/param/license"); (=> $ACTISEDI/param)
	my $path = shift;
	$path =~ s/\\/\//g;
	my $dirname = ".";
	$dirname = $1 if($path =~ /^(.+)\/[^\/]+$/);
	return $dirname;
}

sub getStemName{
# gets the baseName of a file path, excluding file extension
# arguments: file path
# calls: getBaseName()
# returns: the baseName of given file path (excluding file extension)
# example: getStemName("/edi/TSIM.base.pl"); (=> TSIM.base)
	my $path = shift;
	my $basename = getBaseName($path);
	$basename =~ s/\.[\w\d_\-]{2,4}$//;
	return $basename;
}

sub getBaseName{
# gets the basename of a file path, including file extension
# arguments: file path
# calls: none
# returns: the baseName of given file path (including file extension)
# example: getBaseName("/edi/TSIM.base.pl"); (=> TSIM.base.pl)
	my $path = shift;
	$path =~ s/\\/\//g;
	my $basename = $path;
	$basename = $1 if($path =~ /([^\/]+)$/);
	return $basename;
}

sub urldecode{
	my $str = shift;
	$str =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
	$str =~s/\&#(\d+);/chr($1)/eg;
	return $str;
}
sub getFileExt{
# returns file extension of file
# arguments: file path
# calls: none
# returns: file extension
# example: getFileExt("/tmp/test.txt"); (=> txt)
	my $path = shift;
	my $ext = "";
	$ext = $1 if($path=~/\.([\w\d\-_]+)$/);
	return $ext;
}
# get date of LastModified
sub getFileLM{
# returns file last modified time stamp
# arguments: file path
# calls: none
# returns: file last modified time stamp or -1 (if file doesn't exist)
# example: getFileLM("$ACTISEDI/param/license"); (=> 1494083613)
	my $file = shift;
	return -1 if(!-e $file);
	my @infos = stat($file);
	return $infos[9];
}
sub trim{
	my $str = shift;
	$str =~ s/^\s+//;
	$str =~ s/\s+$//;
	return $str;
}
sub camelCase{
	my $msg = shift;
	return uc(substr($msg, 0, 1)) . substr($msg, 1);
}
sub arrayUnique {
	my %seen;
	grep !$seen{$_}++, @_;
}

sub inArray{
	my $elem = shift;
	my @arr = @_;
	foreach my $a(@arr){
		return 1 if($elem eq $a);
	}
	return 0;
}

sub sec2time{
	my $sec = shift;
	my $arg2 = shift;
	my $mode = "normal";
	$mode = $arg2 if($arg2 eq "nohours");
	my $h = d2(int($sec/3600));
	$sec -= $h*3600;
	my $m = d2(int($sec/60));
	$sec -= $m*60;
	my $s = d2($sec);
	if($mode eq "nohours"){
		$m = d2(int($m) + 60*int($h));
		return "$m:$s";
	}
	return "$h:$m:$s";
}

sub time2sec{
	my $time = shift;
	my $mode = shift;
	$mode = "full" if($mode!~/\S/); # full | int
	my ($h, $m, $s) = split(/:/, $time);
	my $f = "";
	if($s=~/\.(\d+)$/){
		$f = $1;
		$s =~ s/\.\d+$//;
	}
	$h = "00" if($h!~/\S/);
	$m = "00" if($m!~/\S/);
	$s = "00" if($s!~/\S/);
	my $res = int($h)*3600 + int($m)*60 + int($s);
	$res .= ".$f" if($f=~/\S/ and $mode ne "full");
	return $res;
}

sub round2dec{
	my $nr = shift; # 3.5714237 - 1 - 2.5
	my $f = 0;
	$nr = int($nr*1000)/10; # 357,1 - 100 - 250
	$f = $1 if($nr=~/[,\.](\d+)$/); # 1 - 0 - 0
	$nr = $1 if($nr=~/^(\d+)[,\.]/); # 357 - 100 - 250
	$nr++ if($f>=5); # 357 - 100 - 250
	$nr /= 100; # 3.57 - 1 - 2.5
	$nr .= ".00" if($nr=~/^\d+$/); # 3.57 - 1.00 - 2.5
	$nr .= "0" if($nr=~/^\d+\.\d$/); # 3.57 - 1.00 - 2.50
	return $nr;
}

sub resolveLink{
	my $flink = shift;
	use Cwd 'abs_path';
	return abs_path($flink);
}

sub getRandomNumber{
	my $max = shift;
	$max = 1000 if($max!~/\S/);
	return int(rand($max));
}

sub getRandomOfRange{
	my $min = shift;
	my $max = shift;
	return $min + int(rand( $max - $min + 1 ));
}

sub timestamp2date{
	my $ts = shift;
	my ($S, $M, $H, $d, $m, $Y) = localtime($ts);
	$m += 1;
	$Y += 1900;
	return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $Y, $m, $d, $H, $M, $S);
}
sub date2timestamp{ # convert a date [YY]YY-MM-DD [hh:ss:[mm]] to a timestamp
	my $datetime = shift;
	$datetime .= " 00:00:00" if($datetime=~/^\d+\-\d{2}\-\d{2}$/);
	my @elems = split(/\s+/, $datetime);
	my $time = pop(@elems);
	$time = trim($time);
	$time = "00:00" if($time!~/\S/);
	$time .= ":00" if($time=~/^\d\d:\d\d$/);
	my @timeelems = split(/:/, $time);
	my $hour = d2($timeelems[0]);
	my $minute = d2($timeelems[1]);
	my $second = d2($timeelems[2]);
	my $date = date2mysql(join(" ", @elems));
	my($year, $month, $day) = split(/\-/, $date);
	$year = "20$year" if(length($year)==2 and $day=~/\S/);
	if($day!~/\S/){
		$day = $month;
		$month = $year;
		my ($tsec, $tmin, $thour, $tday, $tmon, $tyear) = localtime(time);
		$year = $tyear;
	}
	use Time::Local;
	$month--;
	timelocal("$second","$minute","$hour",$day,$month,$year);
}
sub date2mysql{
	my $val = shift;
	my $date = "";
	$val = trim($val);
	$date = "$3-$2-$1" if($val=~/^(\d\d)\.(\d\d)\.(\d\d\d\d)/);
	$date = "$1-$2-$3" if($val=~/^(\d\d\d\d)\-(\d\d)\-(\d\d)/);
	$date = "$3-$2-$1" if($val=~/^(\d\d)\/(\d\d)\/(\d\d\d\d)/);
	$date = "$3-$2-$1" if($val=~/^(\d\d)\-(\d\d)\-(\d\d\d\d)/);
	if($val=~/(\d+)[stndrh\.]{0,2}\s*(\w{3,})\s*(\d\d\d\d)/i or $val=~/(\d\d\d\d)\s*(\w{3,10})\s*(\d+)\s*[stndrh\.]{0,2}/i){
		my $day = trim($1);
		my $mname = trim($2);
		my $year = trim($3);
		if($day=~/\d{4}/){
			my $tmp = $year;
			$year = $day;
			$day = $tmp;
		}
		$mnr = 1;
		$mnr = 2 if($mname=~/feb/i);
		$mnr = 3 if($mname=~/m[a.]r/i);
		$mnr = 4 if($mname=~/apr/i);
		$mnr = 5 if($mname=~/ma[yi]/i);
		$mnr = 6 if($mname=~/jun/i);
		$mnr = 7 if($mname=~/jul/i);
		$mnr = 8 if($mname=~/aug/i);
		$mnr = 9 if($mname=~/sep/i);
		$mnr = 10 if($mname=~/o[ck]t/i);
		$mnr = 11 if($mname=~/nov/i);
		$mnr = 12 if($mname=~/de[cz]/i);
		$date = "$year-". d2($mnr) ."-$day";
	}
	return $date;
}
sub printEnvironment{
	foreach $k(keys(%ENV)){
		printlg("$k => $ENV{$k}");
	}
}
