#!/usr/bin/perl
#
# BNCweb: A user-friendly interface to the British National Corpus - Version 4.3
# Copyright (C) 2005-10 Hoffmann/Evert/Lehmann
#
# Updates and information available at http://www.bncweb.info
#
# This file is part of BNCweb.
# 
# BNCweb is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# 
# BNCweb is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

#
# based on BNCweb Version 2.0:
# © 1996/2004 Lehmann/Hoffmann/Schneider
#

$|=1;

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

print <<END;

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
	<HEAD>

		<TITLE>BNCweb Query result</TITLE>

		<META NAME="generator" CONTENT="BBEdit 4.5">
		<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
	</HEAD>
	<BODY BGCOLOR="#FFFFFF">

END

	
	# required libs
	use Socket;

	use lib "../lib_files";
	use bncLibCQPXML;
	
	use bncConfigXML;
	use Time::HiRes qw (time);
	# settings
	$dispClean = "context.pl";
	$thisProg  = "main.pl";
	$downLoad  = "BNCdownload.pl";
	$fileInfo  = "fileInfo.pl";
	
	$referer=$ENV{'HTTP_REFERER'};
	$username = $ENV{'REMOTE_USER'};
	$qString = $ENV{'QUERY_STRING'};
	$theTime = int(time);

  ### no longer supported -- check if some regexps need //m modifier
  # $*=1; 
	$| =1;
	
	# connect to mysql
	use DBI;
	$bncHandle = DBI->connect("DBI:mysql:$bwMYSQLtable:$bwMYSQLhost:$bwMysqlPort", "$bwMysqlUser", "$bwMysqlPwd");
	$userHandle = DBI->connect("DBI:mysql:$bwMYSQLusertable:$bwMYSQLhost:$bwMysqlPort", "$bwMysqlUser", "$bwMysqlPwd");
	$categorizeHandle = DBI->connect("DBI:mysql:$bwMYSQLcategorizetable:$bwMYSQLhost:$bwMysqlPort", "$bwMysqlUser", "$bwMysqlPwd");

	if ($bwMysqlAuth) {
		$authLevel = &checkAuthLevel;
	} else {
		$authLevel = 1;
	}

		
	unless (getParams($ENV{'QUERY_STRING'})) {
		bark("incomplete transmition of URL<BR>This problem is likely to occur in combination with proxy servers<BR>turn off your web-proxy and try again");
	}
	
	$theTime++ if ($params{thMode} == 1);
	$userCheck = $username . "_" . $theTime;


	#setParam("theData", &decURL($params{theData}));
	
# 	if ($params{theData}=~m/\650/) {
# 		$theData = $params{theData};
# 		$theData=~s/\650/\'/g;
# 		setParam("theData", "$theData");
# 	}

	# remove trailing spaces and returns from the input
	$theData = $params{theData};
	$OriginaltheData = $params{theData};

	$theData=~s/(\r|\s)+\Z//;
	
	# Is this some kind of linewrap??? Check! (25.7.2005)
	$theData=~s/%D%A//g;
		
	$check = $theData=~m/ª/;
	if ($check) {
		$theData = $`;
		
		$theRestrictions = $';
		# fudge for different encodings - this must go!
		$theData=~s/[\200-\777]\Z//;
		($writtenRes, $spokenRes) = split(/##/, $theRestrictions);
		if (($writtenRes) && (!$spokenRes)) {
			$metatextualRestr = "$writtenRes";
		} elsif ((!$writtenRes) && ($spokenRes)) {
			$metatextualRestr = "$spokenRes";
		} else {
			$metatextualRestr = "$writtenRes AND $spokenRes";
		}
		$metatextualQuote = $bncHandle->quote($metatextualRestr);
				
	} else {
		# shouldn't get here
	}
	
	setParam("theData", "$theData");
	
	
	# this is for tooltips to be displayed or not
	$sqlQuery = "SELECT show_value, showRandom FROM settings where user='$username'";
	$sth = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
	$sth->execute or bark("Can't execute $sqlQuery: ". $sth::errstr);
	@rowArray=$sth->fetchrow_array;
	$showTooltip=$rowArray[0];
	$showRandom=$rowArray[1];
	
	# set defaults
	setParam("program", "search") unless $params{program};
	setParam("subcorpus", "no_subcorpus") unless $params{subcorpus};
	setParam("queryType", "word") unless $params{queryType};
	setParam("view", "list") unless $params{view};
	setParam("view2", "nonrandom") unless (($params{view2}) || ($params{categorize} eq "yes"));
		
	# fudge for lancaster lemma scheme in CQL query
	setParam("lemmaScheme", "lancaster") if ($params{theData}=~m/\^\".*=[A-Z]+/);
	
	$shortSQL="";

	# can probably delete this!
	$check = $params{SQL} =~ s/Ï·(\S+)\Z//;
	if ($check) {
		setParam("subcorpus", "$1");
		($fnumList, $spowri) = &subCorporaList($username, $params{subcorpus});
		$params{SQL} .= $fnumList;
		setParam("SQL", "$params{SQL}");
	}
			
	if ($params{ot}=~m/before(\d)/) {
		$sortpos = $1;
		$reverseOrderType = "";
		for ($i = $sortpos+1; $i < 6; $i++) {
			$reverseOrderType .= ", before$i";
		}
		$reverseOrderType = ", after1" if ($sortpos == 5);
	} elsif ($params{ot}=~m/after(\d)/) {
		$sortpos = $1;
		$reverseOrderType = "";
		for ($i = $sortpos+1; $i < 6; $i++) {
			$reverseOrderType .= ", after$i";
		}
		$reverseOrderType = ", before1" if ($sortpos == 5);
	} else {
		$reverseOrderType = ", after1, after2, after3, after4, after5";
	}
	
	# variable for display of query
	$theDataL = $params{theData};
	$theDataL =~ s/</&lt;/g;
	$theDataL =~ s/>/&gt;/g;
				
	#fiddle with thin status indicator
	$originalNumOfSolutions=0;
	$thinSelector='' if ($params{thMode}=~m/##T\d#\d+(#G)?\Z/);
	# set kwic variables
	if ($params{view} eq "kwic") {
		$reverseView="list";
		$reverseBut="Show Sentence View";
		$leftContext=120;
		$rightContext=135;
	} else {
		$reverseView="kwic";
		$reverseBut="Show KWIC View";
	}
	

	if ($params{max} ne "INIT") {
		if ( ($params{max} < $params{chunk}) || ($params{chunk} < 1) ) {
			bark("$params{chunk} is not a valid pagenumber, please try again.");
		}
	}
	
	if ($params{program} eq "search") {
		# first query will update history database
		unless ($params{recreate}) {
			if ($params{qname} eq "INIT") {
				$firstQuery = 1;
			} else {
				$firstQuery = 0;
			}
		}
		$listFiles=$params{listFiles};

		if (($firstQuery) && ($theRestrictions)) {
			if (($writtenRes) && (!$spokenRes)) {
				$textOrSpeaker = "text";
			} elsif ($spokenRes) {
				$textOrSpeaker = "speaker";
			}
			
			$typeOfRestriction = "metatext";
			$quoteItems = '""';
		} elsif (($firstQuery) && (!$theRestrictions)) {
			$check = 0;
			
			if ($params{qtype} eq "0") {
				$typeOfRestriction = "-";
			} elsif ($params{qtype} eq "1") {
				$typeOfRestriction = "written";
				$textOrSpeaker = "text";
			} elsif ($params{qtype} eq "2") {
				$typeOfRestriction = "spoken";
				$textOrSpeaker = "text";
			} elsif ($params{qtype} eq "last_written") {
				$typeOfRestriction = "metatext";
				$check++;
			} elsif ($params{qtype} eq "last_spoken") {
				$typeOfRestriction = "metatext";
				$check++;
			} else {
				$typeOfRestriction = "subcorpus";
				$check++;
			}
			
			if ($check) {

				$subcorpusQuote = $bncHandle->quote($params{qtype});
				$sqlQuery = "SELECT fnums, metatextual, textOrSpeaker FROM subcorpora where username = '$username' and subcorpus = $subcorpusQuote";
				$sth = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: $bncHandle::errstr");
				$sth->execute or bark("Can't execute $sqlQuery: $sth::errstr");
				@rowArray=$sth->fetchrow_array;
				$items=$rowArray[0];
				$metatextual=$rowArray[1];
				$textOrSpeaker=$rowArray[2];
				if ($params{qtype}=~m/\Alast_(spoken|written)\Z/) {	
					$quoteItems = '""';
				} else {
					$quoteItems = $bncHandle->quote($items);
				}
			} else {
				$quoteItems = '""';
			}
		}
		
		setParam("textOrSpeaker", "$textOrSpeaker") if ($textOrSpeaker);		
		
		# put query in history
		if ($firstQuery) {
			unless ($listFiles) {
				$insertTheData = $params{theData};
				$insertTheData = $bncHandle->quote($insertTheData);
				if ($typeOfRestriction eq "metatext") {
					$theRestrictionsQuote = $metatextualQuote;
				} elsif ($typeOfRestriction eq "subcorpus") {
					$theRestrictionsQuote = $subcorpusQuote;
				} else {
					$theRestrictionsQuote = "''";
				}
				if ($params{qtype}=~m/\Alast_(spoken|written)\Z/) {					
					$theRestrictionsQuote = $bncHandle->quote($metatextual);
				}
				$theOriginalURL = $bncHandle->quote($qString);
				$theSimpleQuery = $bncHandle->quote($params{simpleQuery});
				
				$sqlQuery = "SELECT count(*) FROM history where checked = '$userCheck'";
				$sth = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: $bncHandle::errstr");
				$sth->execute or bark("Can't execute $sqlQuery: $sth::errstr");
				@rowArray=$sth->fetchrow_array;
				$countConcurrent=$rowArray[0];
				if (!$countConcurrent) {
					$sqlQuery = "insert into history (user, link, query, hits, checked, subcorpus, typeOfRestriction, items, textOrSpeaker, simple_query, queryMode) values ('$username', $theOriginalURL, $insertTheData, -3, '$userCheck', $theRestrictionsQuote, '$typeOfRestriction', $quoteItems, '$textOrSpeaker', $theSimpleQuery, '$params{queryMode}')";
					$bncHandle->do($sqlQuery) or bark("Can't insert $sqlQuery: " . $bncHandle::errstr);	
				} else {
					bark("two queries by the same user during the same second<BR>This may have occurred because you have double-clicked on the [Submit] button - a single click is sufficient.<BR>It could also be because your username is logged in on more than one computer or because you have automated BNCweb in order to perform many queries successively.");
				}
			}
		}		
	} elsif ($params{program} eq "sort") {
		if ($params{letter}) {
			$letter=$params{letter};
			$lower=lc($letter);
			$letter="\($letter\|$lower\)";
		}
		$tag = $params{tag};		
		$selected{"$params{tag}"}="SELECTED";
		
	}
	
	setParam("randomize", "random") if (($firstQuery) && ($showRandom eq "yes") && (!$params{listFiles}));
	
    CQPconnect();	
	
	$recreated = 1 if ($params{recreate});
	
	$startTime = time;
	
	#execute query or retrieve old one
	($numOfSolutions, $qName, $numFiles, $inCache, $numOfSpeakers) = solve($params{theData}, $params{chunk}, $params{inst}, $params{qname}, $params{lemmaScheme}) unless ($listFiles);
	
	$endTime = time;
	if ($params{qname} eq "INIT") {
		$timeTaken = int((($endTime - $startTime) * 1000) + 0.5)/ 1000;
	}
	
	if (($params{qname} eq "INIT") || ($recreated)) {
		setParam("qname","$qName");
	} 

	setParam("numOfFiles","$numFiles") unless ($params{numOfFiles});

	# calculate the total number of words for the query
	if ($listFiles) {
				
		if (($writtenRes) && (!$spokenRes)) {
			$sqlQuery = "SELECT sum(numwords) FROM headerInfo WHERE $writtenRes";
			$typeOfSubcorpus = "written";
		} elsif ((!$writtenRes) && ($spokenRes)) {
			$sqlQuery = "SELECT sum(speakerWords) FROM speakers WHERE $spokenRes";
			$typeOfSubcorpus = "spoken";
		} elsif ((!$writtenRes) && (!$spokenRes) && ($params{qtype})) {
			if ($params{qtype} == 1) {
				$sqlQuery = "SELECT sum(numwords) FROM headerInfo WHERE spowri = 1";
			} else {
				$sqlQuery = "SELECT sum(numwords) FROM headerInfo WHERE spowri = 2";
			}
			$typeOfSubcorpus = "written";
		} elsif ((!$writtenRes) && (!$spokenRes) && (!$params{qtype})) {
				$sqlQuery = "SELECT sum(numwords) FROM headerInfo";
		} else {
			$sqlQuery = "SELECT sum(speakerWords) FROM speakers, headerInfo WHERE headerInfo.fname = speakers.filename AND $writtenRes AND $spokenRes";
			$typeOfSubcorpus = "wrispo";
		}
		$sth = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
		$sth->execute or bark("Can't execute $sqlQuery: " . $sth::errstr);
		@rowArray=$sth->fetchrow_array;
		$numTotalWords=$rowArray[0];
		if (!$numTotalWords) {
			saySorry("no_files") 
			&printFooter();
			&CQPdisconnect();
			exit(0);
		}
	} else {

		($sqlQuery, $sqlQuery2)=&freqCalculate2($params{theData}, $params{subcorpus}, $username, "main");
		$sth = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
		$sth->execute or bark("Can't execute $sqlQuery: " . $sth::errstr);
		@rowArray=$sth->fetchrow_array;
		$numTotalWords=$rowArray[0];

		
		# NO IDEA WHY I'M DOING THIS...
		$checkSpeakers=$sqlQuery=~s/sum\(speakerWords\)/spid/;
		if ($checkSpeakers) {
			$sth= $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
			$spidSolutions = $sth->execute or bark("Can't execute $sqlQuery: " . $sth::errstr);
			$spidArray=$sth->fetchall_arrayref;
			for ($i = 0; $i < $spidSolutions; $i++) {
				$spids{$spidArray->[$i][0]} = 1;
			}
		}
		$sth = $bncHandle->prepare($sqlQuery2) or bark("Can't prepare $sqlQuery2: " . $bncHandle::errstr);
		$sth->execute or bark("Can't execute $sqlQuery: " . $sth::errstr);
		@rowArray=$sth->fetchrow_array;
		$numTotalWordsOrig=$rowArray[0];
		
	}
		
	# thin data if required
	if ((($params{thMode} eq '0') || ($params{thMode} eq '1') || ($params{thMode} eq '2')) && ($params{program} eq "search")) {
		$performThinning = 1;
		$numOfSolutions = &thin();
		$thinSelector='';
	} else {
		$performThinning = 0;
	}

	if (($numOfSolutions > $bwThinValue) && (!$authLevel)) {
		$forceThin = 1;
	}

	if (($params{program} eq "search") && ($params{thMode} eq "INIT")) {
		$thMode="M" . $numOfSolutions . "#$params{numOfFiles}#$params{subcorpus}##";
		setParam("thMode", "$thMode");
	}

	# changed it to "recreate" from "recreated" - don't know why it was like that
	# 8.5.2006
	&updateSavedQueries if ((!$inCache) && (($params{recreate}) || ($firstQuery)) && (!$listFiles) || ($performThinning));
	
	if ($params{randomize}) {
		$randomView = $params{thMode}=~m/##V#\d+\Z/;
		if (($params{randomize} eq "random") && (!$randomView)) {
			$thMode = $params{thMode} . "##V#$numOfSolutions";
			$inCache = &checkCache($params{theData}, "", "", $thMode);
			
			if ($inCache) {
				setParam("thMode", "$thMode");
				$CQP->exec("set DataDirectory '/$bwTempPath/'");
				$CQP->exec("$bwCorpus");
				$qName = $inCache;
				setParam("qname","$qName");
			} else {
				&randomize();
				&updateSavedQueries;
				$performRandomize = 1;
			}
			setParam("chunk","1");
		}
		
		if (($params{randomize} eq "nonrandom") && ($randomView)) {
			$thMode = $params{thMode};
			$thMode=~s/##V#\d+\Z//; 
			$inCache = &checkCache($params{theData}, "", "", $thMode);
			if ($inCache) {
				setParam("thMode", "$thMode");
				$CQP->exec("set DataDirectory '/$bwTempPath/'");
				$CQP->exec("$bwCorpus");
				$qName = $inCache;
				setParam("qname","$qName");
			} else {
				&unRandomize();
				$performUnRandomize = 1;
			}
			setParam("chunk","1");
		}
	}

	if ($params{thMode}=~m/##V#\d+\Z/) {
		$reverseView2="nonrandom";
		$reverseBut2="Show in corpus order";
	} else {
		$reverseView2="random";
		$reverseBut2="Show in random order";
	}
	
	# update time_of_query in saved queries database
	# older (original) queries would otherwise be deleted even if the query was re-executed afterwards.
	if (($firstQuery) && ($inCache)) {
		$theTime = int(time);
		$sqlQuery = "UPDATE savedQueries set time_of_query=$theTime where originalFile = '$inCache'";
		$bncHandle->do($sqlQuery) or bark("Can't $sqlQuery: " . $bncHandle::errstr);
	}
	
	if (($firstQuery) && (!$listFiles)) {
    	# user statistics...
		$sqlQuery = "update history SET hits = $numOfSolutions where checked = '$userCheck'";
		$bncHandle->do($sqlQuery) or bark("Can't insert $sqlQuery: " . $bncHandle::errstr);
				
		&deleteCachedQueries($bwFileSize);
		
		# delete entries in the mysqlLog database which are older than one hour - in case the server has crashed in the meantime
		$theTime = int(time) - 1800;
		$sqlQuery = "DELETE FROM mysqlLog where crTime < $theTime";
		$bncHandle->do($sqlQuery) or bark("Can't delete: $sqlQuery: " . $bncHandle::errstr);
	}
	
	if ($params{program} eq "sort") {
		if ($params{ot}=~m/refnum#(\S+)/) {
			$orderBy = "refnum";
			$ot = $1;
		} else {
			$orderBy = $params{ot};
			$ot = $params{ot};
		}


		$dbname = $params{dbname};

		#$SQL = "SELECT beginPosition, endPosition, $ot, if ($ot regexp '^[a-z]', 0, 1) as isNull INTO OUTFILE '/$bwMySQLTempPath/${dbname}_new' FROM $params{dbname} ORDER BY isNull, $orderBy $reverseOrderType";
		$SQL = "SELECT beginPosition, endPosition, $ot INTO OUTFILE '/$bwMySQLTempPath/${dbname}_new' FROM $params{dbname} ORDER BY $ot not regexp '^[a-z]', $orderBy $reverseOrderType";
		$thMode=$params{thMode};
		if ($params{changeSort} eq "yes") {
			$thMode =~ s/(.*)##A.*?\Z/$1/ unless ($params{changePosition} eq "yes");
			if ($params{exclude} eq "yes") {
				$thMode .= "##A$params{ot}#L$letter#TE$tag";
			} else {
				$thMode .= "##A$params{ot}#L$letter#TN$tag";
			}			
		}
		setParam("thMode", "$thMode");
		setParam("changePosition","");
		if (($letter) || ($tag)) {
			$tagName=$tag;
			if ($tag eq "VERB") {
				$tagName .= "any verb";
				$tag = "(V..)";
			} elsif ($tag eq "SUBST") {
				$tagName .= "any noun";
				$tag = "(N[NP].|ZZ0)";
			} elsif ($tag eq "CONJ") {
				$tagName .= "any conjunction";
				$tag = "CJ.";
			} elsif ($tag eq "ADJ") {
				$tagName .= "any adjective";
				$tag = "(AJ.|CRD|DT0|ORD)";
			} elsif ($tag eq "ADV") {
				$tagName .= "any adverb";
				$tag = "(AV.|XX0)";
			} elsif ($tag eq "PRON") {
				$tagName .= "any pronoun";
				$tag = "(DPS|DT[SQ]|EX0|PN.)";
			} elsif ($tag eq "STOP") {
				$tagName .= "any punctuation";
				$tag = "(POS|PU.)";
			} elsif ($tag eq "ART") {
				$tagName .= "any article";
				$tag = "AT0";
			} elsif ($tag eq "PREP") {
				$tagName .= "any preposition";
				$tag = "(PR.|TO0)";
			}
		
			# Discuss this with Stefan! This means that a restriction for a single tag will also retrieve ambiguity tags!
			$regexp=1;
			
			if ($letter) {
				$SQL = "SELECT beginPosition, endPosition, $ot, tag$ot INTO OUTFILE '/$bwMySQLTempPath/${dbname}_new' FROM $params{dbname} WHERE $ot regexp '^$letter' ORDER BY $orderBy $reverseOrderType";
			} 

			if ($params{exclude} eq "yes") {
				$tagExclude1 = "not";
				$tagExclude2 = "<>";
			} else {
				$tagExclude1 = "";
				$tagExclude2 = "=";
			}
	

			if ($tag) {
				if ($regexp == 1) {
					if ($letter) {
						$SQL = "SELECT beginPosition, endPosition, $ot, tag$ot INTO OUTFILE '/$bwMySQLTempPath/${dbname}_new' FROM $params{dbname} WHERE tag$ot $tagExclude1 regexp '^$tag' AND $ot regexp '^$letter' ORDER BY $orderBy $reverseOrderType";
					} else {
						$SQL = "SELECT beginPosition, endPosition, $ot, tag$ot INTO OUTFILE '/$bwMySQLTempPath/${dbname}_new' FROM $params{dbname} WHERE tag$ot $tagExclude1 regexp '^$tag' ORDER BY $orderBy $reverseOrderType";
					}
				} else {
					if ($letter) {
						$SQL = "SELECT beginPosition, endPosition, $ot, tag$ot INTO OUTFILE '/$bwMySQLTempPath/${dbname}_new' FROM $params{dbname} WHERE tag$ot $tagExclude2 '^$tag' AND $ot regexp '^$letter' ORDER BY $orderBy $reverseOrderType";
					} else {
						$SQL = "SELECT beginPosition, endPosition, $ot, tag$ot INTO OUTFILE '/$bwMySQLTempPath/${dbname}_new' FROM $params{dbname} WHERE tag$ot $tagExclude2 '^$tag' ORDER BY $orderBy $reverseOrderType";
					}
				}
			}
		}
		$SQL=~s/node\d/node/g;
		setParam("SQL", "$SQL");
	}

	if ($params{SQL}) {
		# display depends on a SQL-query
		$sqlQuery = $params{SQL};
		if ($sqlQuery=~m/INTO OUTFILE \'[^']+\'/) {
		
			$sqlQueryDisplay = $sqlQuery;
			$sqlQueryDisplay=~s/INTO OUTFILE \'[^']+\'//;
			$sqlQueryDisplay=~s/beginPosition, // unless ($params{program} eq "complex");
	
			$oldQname = $qName;
			$inCache = &checkCache($theData, "", $qName, $params{thMode});
			if ($inCache) {
				$CQP->exec("set DataDirectory '/$bwTempPath/'");
				$CQP->exec("$bwCorpus");
								
				($numOfSolutions) = $CQP->exec("size $inCache");
				setParam("SQL", "$sqlQueryDisplay");
				setParam("qname", "$inCache");
				$timeTaken = "cache";
			
			} else {
				
				$qNameNew = "$params{dbname}" . "_new";
				$qNameNew2 = $username . "_" . int(time);
		
				unlink("/$bwTempPath/$qNameNew") if -f "/$bwTempPath/$qNameNew";
				
				$sqlQuery=~s/, dist, item//;
				$sqlQuery=~s/, (after\d|before\d|node)(, tag(after\d|before\d|node))?//;
				$sth = $userHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
				$sth->execute or bark("Can't execute $sqlQuery: ". $sth::errstr);
				$numOfSolutions=$sth->rows;
				
				
				if (!$numOfSolutions) {
					# sql-query has no solutions
					print <<END;
						<H2>No matches!</H2>
END
					&printFooter();
					&CQPdisconnect();
					exit(0);
				} else {
					# prepend number of hits to output file
					qx{echo $numOfSolutions | cat - '/$bwTempPath/$qNameNew' > '/$bwTempPath/$qNameNew2'};
					unlink("/$bwTempPath/$qNameNew") if -f "/$bwTempPath/$qNameNew";
					
					$CQP->exec("undump $qNameNew2 < '/$bwTempPath/$qNameNew2'");
		
					unlink("/$bwTempPath/$qNameNew2") if -f "/$bwTempPath/$qNameNew2";
					
					$CQP->exec("set DataDirectory '/$bwTempPath/'");
					$CQP->exec("$bwCorpus");
					
					$CQP->exec("save $qNameNew2");
					@stat = stat("/$bwTempPath/$bwCorpus:$qNameNew2");
					$fileSize = $stat[7];
					
					setParam("SQL", "$sqlQueryDisplay");
					
					setParam("qname", "$qNameNew2");
	
					# put query in saved queries database 
					$theTime = int(time);
					$thModeInsert = $params{thMode};
					
					$thModeInsert=~m/\AM\d+#\d+#([^#]+)/;
					$checkSubcorp = $1;
					$subcorpusInsert="";
					unless ($checkSubcorp eq "no_subcorpus") {
						$subcorpusInsert = "###" unless ($checkSubcorp=~m/=/);
					}
					
					$thModeInsert = $bncHandle->quote($thModeInsert);
	
					$theDataLink = "$params{theData}";
					$theDataLink=~s/(\W)/sprintf("%%%x", ord($1))/eg;
					$theDataLink = "theData=" . $theDataLink . "&chunk=1&inst=$params{inst}&max=$params{max}";
					$theDataLinkQuote = $bncHandle->quote($theDataLink);
	
					$sqlQuery = "SELECT query, simpleQuery, originalFile FROM savedQueries where queryID='$params{theID}'";
					$sth9 = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
					$sth9->execute or bark("Can't execute $sqlQuery: ". $sth9::errstr);
					@rowArray=$sth9->fetchrow_array;
					$sQuery = $rowArray[0];
					$sSimpleQuery = $rowArray[1];
					$sOriginalFile = $rowArray[2];
	
					$insertTheData = $bncHandle->quote($sQuery);
					$insertTheDataSimple = $bncHandle->quote($sSimpleQuery);
					
	
					$sqlQuery = "insert into savedQueries (user, queryID, query, simpleQuery, hits, time_of_query, saved, link, initialQuery, originalFile, theID, fileSize, subcorpus, thMode) 
							values 
						('$username', '$qNameNew2', $insertTheData, $insertTheDataSimple, $numOfSolutions, $theTime, 0, $theDataLinkQuote, 0, '$qNameNew2', '$params{theID}', $fileSize, '$subcorpusInsert', $thModeInsert)";
	
					$bncHandle->do($sqlQuery) or bark("Can't insert $sqlQuery: " . $bncHandle::errstr);
					
					setParam("queryID", "$qNameNew2");
	
	
					
				}
			}
		}
		
		$sqlQuery = $params{SQL};

		# don't do this if coming from distribution analysis
		unless ($params{program} eq "distribution") {
			$sth = $userHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
			$sth->execute or bark("Can't execute $sqlQuery: ". $sth::errstr);
			$resArray=$sth->fetchall_arrayref;
		}
	
		
		# we can probably delete the first if-bracket
		if (($params{program} eq "subcorpus") && ($params{subcorpus} ne "no_subcorpus")) {
			$thMode = $params{thMode};
			$thMode =~ s/##G[^#]+\Z//;
			$thMode .= "##G$params{subcorpus}#$numOfSolutions";
			setParam("thMode", "$thMode");
			setParam("SQL", "$shortSQL");
		} elsif (($params{program} eq "sort") && ($params{changeSort} eq "yes")) {
			$thMode = $params{thMode};
			$thMode .= "#H$numOfSolutions";
			setParam("thMode", "$thMode");
			setParam("changeSort", "");
		}
	}
	
	if ($listFiles) {
		($writtenRes, $spokenRes) = split(/##/, $theRestrictions);
		if (($writtenRes) && (!$spokenRes)) {
			$sqlQuery = "SELECT fname, numwords, numSentences, numSentences, title FROM headerInfo WHERE $writtenRes ORDER BY fname";
			$spokenTD = "";
			$subcorpus = $writtenRes;
		} elsif ((!$writtenRes) && ($spokenRes)) {
			$sqlQuery = "SELECT spid, speakerWords, speakerTurns, filename FROM speakers WHERE $spokenRes";
			$spokenTD = "<TD NOWRAP WIDTH=\"8%\" BGCOLOR=\"#FFCC66\"><B>Speaker-ID</B></TD>";
			$subcorpus = $spokenRes;
		} elsif ((!$writtenRes) && (!$spokenRes) && ($params{qtype})) {
			if ($params{qtype} == 1) {
				$sqlQuery = "SELECT fname, numwords, numSentences, numSentences, title FROM headerInfo WHERE spowri = 1";
			} else {
				$sqlQuery = "SELECT fname, numwords, numSentences, numSentences, title FROM headerInfo WHERE spowri = 2";
			}
			$spokenTD = "";
			$subcorpus = "spowri=" . $params{qtype};
		
		} elsif ((!$writtenRes) && (!$spokenRes) && (!$params{qtype})) {
				$sqlQuery = "SELECT fname, numwords, numSentences, numSentences, title FROM headerInfo";
		} else {
			$sqlQuery = "SELECT spid, speakerWords, speakerTurns, filename, title FROM speakers, headerInfo WHERE headerInfo.fname = speakers.filename and $writtenRes AND $spokenRes";
			$spokenTD = "<TD NOWRAP WIDTH=\"8%\" BGCOLOR=\"#FFCC66\"><B>Speaker-ID</B></TD>";
			$subcorpus = $writtenRes . " AND " . $spokenRes;
		}
		
		$sth4 = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
		$sth4->execute or bark("Can't execute $sqlQuery: ". $sth::errstr);
		$resArray4=$sth4->fetchall_arrayref;
		$numOfSolutions = $sth4->rows;

	}
	setParam("numOfSolutions", "$numOfSolutions") unless ($params{numOfSolutions});

	if ($numOfSolutions) {
		&createNavigationLinks() unless ($params{inst} eq "count hits");
		&printNavigation(0) unless ($forceThin);
	
		unless (($params{inst} eq "count hits") || ($forceThin)){
	
			# get sentences and print
			$showResult=($start + 1);
			
			# print titlebar
			if ($params{view} eq "kwic") {
				$colSpan='COLSPAN=3';
				$nowrap=' NOWRAP ALIGN="RIGHT"';
				$bounding='p';
			} else {
				if ($listFiles) {
					$colSpan='COLSPAN=2';
				} else {
					$colSpan='';
				}
				$nowrap='';
				$bounding='s';
			}
	
			if ($params{categorize} eq "yes") {
	
				$sqlQuery = "SELECT theValues FROM categorize WHERE theName='$params{dbname}'";
				$sth= $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
				$sth->execute or bark("Can't execute $sqlQuery: " . $sth::errstr);
				@array=$sth->fetchrow_array;
				$theValues=$array[0];
				@theValues = split(/\W/, $theValues);
	
				print <<"END";
					<TABLE BORDER="0" CELLPADDING="2" WIDTH="100%" BGCOLOR="#FFFFFF">
						<TR>
							<TD WIDTH="3%" ALIGN="RIGHT" BGCOLOR="#FFCC66"><B>No</B>&nbsp;</TD>
							<TD WIDTH="8%" ALIGN="CENTER" BGCOLOR="#FFCC66">
								<P ALIGN="CENTER"><B>Filename</B>
							</TD>
							$spokenTD
							<TD WIDTH="86%" BGCOLOR="#FFCC66" $colSpan>
								<P ALIGN="CENTER"><B>Hits $showResult to $end&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pageInd</B>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
							</TD>
							<TD WIDTH="3%" BGCOLOR="#FFCC66">
								<B>Categories</B>
							</TD>
							<FORM ACTION="/$bwCGIalias/categorizeAdmin.pl" METHOD="GET">
								<INPUT TYPE="hidden" NAME="action" VALUE="update">
								<INPUT TYPE="hidden" NAME="chunk" VALUE="$params{chunk}">
								<INPUT TYPE="hidden" NAME="categorize" VALUE="yes">
								<INPUT TYPE="HIDDEN" NAME="theData" SIZE="-1" VALUE="$theData2">
								<INPUT TYPE="hidden" NAME="inst" VALUE="$params{inst}">
								<INPUT TYPE="hidden" NAME="max" VALUE="$params{max}">
								<INPUT TYPE="hidden" NAME="qname" VALUE="$params{qname}">
								<INPUT TYPE="hidden" NAME="queryID" VALUE="$params{queryID}">
								<INPUT TYPE="hidden" NAME="thMode" VALUE="$params{thMode}">
								<INPUT TYPE="hidden" NAME="thin" VALUE="$params{thin}">
								<INPUT TYPE="hidden" NAME="qtype" VALUE="$params{qtype}">
								<INPUT TYPE="hidden" NAME="view" VALUE="$params{view}">
								<INPUT TYPE="hidden" NAME="program" VALUE="$params{program}">
								<INPUT TYPE="hidden" NAME="SQL" VALUE="$params{SQL}">
								<INPUT TYPE="hidden" NAME="word" VALUE="$params{word}">
								<INPUT TYPE="hidden" NAME="dbname" VALUE="$params{dbname}">
								<INPUT TYPE="hidden" NAME="distance" VALUE="$distance">
								<INPUT TYPE="hidden" NAME="ot" VALUE="$params{ot}">
								<INPUT TYPE="hidden" NAME="exclude" VALUE="$params{exclude}">
								<INPUT TYPE="hidden" NAME="letter" VALUE="$params{letter}">
								<INPUT TYPE="hidden" NAME="theID" VALUE="$params{theID}">
								<INPUT TYPE="hidden" NAME="tag" VALUE="$params{tag}">
						</TR>
END
			} else {
				print <<"END";
					<TABLE BORDER="0" CELLPADDING="2" WIDTH="100%" BGCOLOR="#FFFFFF">
						<TR>
							<TD WIDTH="3%" ALIGN="RIGHT" BGCOLOR="#FFCC66"><B>No</B>&nbsp;</TD>
							<TD WIDTH="8%" ALIGN="CENTER" BGCOLOR="#FFCC66">
								<P ALIGN="CENTER"><B>Filename</B>
							</TD>
							$spokenTD
							<TD WIDTH="89%" BGCOLOR="#FFCC66" $colSpan>
								<P ALIGN="CENTER"><B>Hits $showResult to $end&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pageInd</B>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
							</TD>
						</TR>
END
			}
			
			$printCount = 0;
			$theList="";

#################################
			unless ($listFiles) {
				if ($params{view} eq "list") {
					$CQP->exec("set Context 1 s");
				} else {
					$CQP->exec("set Context 12 words");
				}
				$CQP->exec("show -cpos");
				$CQP->exec("show +word +pos +space_after +tags_before +tags_after +type");
				#$CQP->exec("show +pos +div +head +quote +sp +speaker +stage +lg +l +list +label +item +note +bibl +p +u +s +corr +hi +mw +trunc +space_after");
				#$CQP->exec("show +anchors");
				
				
				$CQP->exec("set LeftKWICDelim '--%%%--'");	
				$CQP->exec("set RightKWICDelim '--%%%--'");	
				
				$batch_end = $end - 1;
				
				#warn "$start $batch_end";
				@kwic = $CQP->exec("cat $params{qname} $start $batch_end");
				@table = $CQP->dump("$params{qname}", $start, $batch_end); # table of corpus positions
					
				
				$n = @kwic;	
			} else {
				$n = $end - $start;
			}
			
			if ($forceThin) {
				
				print <<"END";
					</TABLE><TABLE BORDER="0" CELLPADDING="2" WIDTH="100%" BGCOLOR="#FFFFFF">
						<TR><TD height=90 valign=\"middle\">
						<h3>Your query result has more than 50,000 hits and can therefore not be displayed.</h3>Please select \"Thin\" from the post-query options menu and randomly reduce
						your query result to 50,000 hits or less.
						</TD>
						</TR>
END
			} else {
			
			
				theLoop: foreach $i (0 .. $n-1) {
					$solutionNum = $start + $i;
					$counter = ($solutionNum + 1);
					#warn "before: $solutionNum";
		
					# get the solution number from the database
					if (($params{SQL}) && ($params{program} eq "collocations")) {
						#$solutionNum=$resArray->[$i][0];
						$colDist=$resArray->[$solutionNum][1];
						$colWord=$resArray->[$solutionNum][2];
					}
					$colWord=~s/_/ /g;
					$colWord=~s/~/ /g;
					
					if ($params{program} eq "sort") {
						$theWord=$resArray->[$solutionNum][1];
						$theTag=$resArray->[$solutionNum][2];
						$theWord=~s/_/ /g;
					}
		
					$printCount++;
					($kwic_lc, $kwic_match, $kwic_rc) = split /--%%%--/, $kwic[$i];
					
		
					if ($listFiles) {
						$nWords=makeDecimals($resArray4->[$solutionNum][1]);
						$nTurnsorSentences=makeDecimals($resArray4->[$solutionNum][2]);
						$title=$resArray4->[$solutionNum][4];
		
						if ((($writtenRes) && (!$spokenRes)) || ((!$writtenRes) && (!$spokenRes))) {
							$theTextID=$resArray4->[$solutionNum][0];
							$line = "$title - $nWords w-units, $nTurnsorSentences s-units";
						} else {
							$spid=$resArray4->[$solutionNum][0];
							$theTextID=$resArray4->[$solutionNum][3];
							$sqlQuery = "SELECT filename, age, dialect, education, firstLanguage, sex, class, ageFull, 
									nameFull, occupation, role, num_orthogr_words, numtokens, speakerWords, speakerPuns, speakerTurns, speakerSunits  
									FROM speakers WHERE spid = '$spid'";
							$sth5 = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
							$sth5->execute or bark("Can't execute $sqlQuery: " . $sth5::errstr);
							
							($filename, $age, $dialect, $education, $firstLanguage, $sex, $class, $ageFull, 
							$nameFull, $occupation, $role, $num_orthogr_words, $numtokens, $speakerWords, $speakerPuns, $speakerTurns, $speakerSunits ) = $sth5->fetchrow_array;
							
							$value = "age=$age";
							#warn $value;
							$ageInfo = $catValues{$value};
							$value = "dialect=$dialect";
							$dialectInfo = $catValues{$value};
							$value = "education=$education";
							$educationInfo = $catValues{$value};
							$value = "firstLanguage=$firstLanguage";
							$firstLanguageInfo = $catValues{$value};
							$value = "sex=$sex";
							$sexInfo = $catValues{$value};
							$value = "class=$class";
							$classInfo = $catValues{$value};
							$theDesc = "<i>$typeValues{sex}:</i> $sexInfo<BR> <i>$typeValues{age}:</i> $ageInfo<BR> <i>$typeValues{class}:</i> $classInfo<BR> ";
							$theDesc .= "<i>$typeValues{education}:</i> $educationInfo<BR> <i>$typeValues{firstLanguage}:</i> $firstLanguageInfo<BR> ";
							$theDesc .= "<i>$typeValues{dialect}:</i> $dialectInfo<BR> <i>Name:</i> $nameFull<BR> <i>Occupation:</i> $occupation<BR> <i>Role:</i> $role";
							
							$line = "<A HREF=\"/$bwCGIalias/speakerInfo_new.pl?text=$theTextID&spid=$spid&urlTest=yes\">$spid</A></td><td>$theDesc</td>";
						}
				
						($link2, $markup) = &createFileLink($theTextID);
						$text = $theTextID;
						$lineIndicator = $solutionNum;
						$num=0;
					} else {
						($line, $lineIndicator, $num, $link2) = printIt($kwic_lc, $kwic_match, $kwic_rc, $solutionNum);
					}
					
					if ($num) {
						print '<TR VALIGN="Top" BGCOLOR="#DDDDDD"><TD ALIGN="RIGHT"><B>' . "$counter</B></TD>". '<TD ALIGN="LEFT" NOWRAP>' . "&nbsp;$link2$text $num</A>&nbsp;</TD>";
					} else {
						print '<TR VALIGN="Top" BGCOLOR="#DDDDDD"><TD ALIGN="RIGHT"><B>' . "$counter</B></TD>". '<TD ALIGN="LEFT" NOWRAP>' . "&nbsp;$link2$text</A>&nbsp;</TD>";
					}
					$addCheckBox="";
					if ($listFiles) {
						if ($spokenTD) {
							$addCheckBox="<TD VALIGN=\"MIDDLE\">&nbsp;<INPUT TYPE=\"CHECKBOX\" NAME=\"t\" VALUE=\"$spid\"></TD>";
							$theList .= "·$spid";
						} else {
							$fnum = &Filemapping($theTextID);
							$theList .= "·$fnum";
							$addCheckBox="<TD VALIGN=\"MIDDLE\">&nbsp;<INPUT TYPE=\"CHECKBOX\" NAME=\"t\" VALUE=\"$fnum\"></TD>";
						}
					}
					if ($params{categorize} eq "yes") {
						$sqlQuery = "SELECT catName FROM $params{dbname} where refnumber=$counter";
						$sth7 = $categorizeHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $categorizeHandle::errstr);
						$sth7->execute or bark("Can't execute $sql: $sth7::errstr");
						@rowArray7=$sth7->fetchrow_array;
						$theCat = $rowArray7[0];
						
						
						undef %checkedCat;
						$addSelect = "<SELECT NAME=\"cat$counter\">";
						
						if ($theCat) {
							$checkedCat{$theCat} = "SELECTED";
						} else {
							$addSelect .= "<OPTION SELECTED> </OPTION>";
						}
						
						foreach $theValue (@theValues) {
							$addSelect .= "<OPTION $checkedCat{$theValue}>$theValue</OPTION>";
						}
						
						$addSelect .= "</SELECT>";
						
						$addCheckBox="<TD VALIGN=\"TOP\">$addSelect</TD>";
					}
					print "<TD $nowrap>$line</TD>$addCheckBox</TR>\n";
		
				}
			}
			
			if ($listFiles) {
				if ($spokenTD) {
					$colspan = "5";
				} else {
					$colspan = "4";
				}
				print <<END;
					<TR VALIGN="MIDDLE" BGCOLOR="#DDDDDD">
						<TD COLSPAN="$colspan" HEIGHT="27" ALIGN="RIGHT">
							include all files on this page &nbsp;<INPUT TYPE="CHECKBOX" NAME="all" VALUE="$theList">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
						</TD>
					</TR>
				<INPUT TYPE="hidden" NAME="urlTest" VALUE="yes">
				</FORM>
END
			} elsif ($params{categorize} eq "yes") {
				if ($params{view} eq "kwic") {
					$colSpan = "6";
				} else {
					$colSpan = "4";
				}
				print <<END;
					<TR VALIGN="MIDDLE" BGCOLOR="#DDDDDD">
						<TD COLSPAN="$colSpan" ALIGN="RIGHT">
							<SELECT NAME="Leave">
								<OPTION>Save values and leave categorization mode</OPTION>
								<OPTION SELECTED>Save categorization values for this page!</OPTION>
								<OPTION VALUE="New Query">New Query (does not save changes!)</OPTION>
							</SELECT>
							<INPUT TYPE="hidden" NAME="urlTest" VALUE="yes">
							<INPUT TYPE="SUBMIT" VALUE="Go!">
							</FORM>
						</TD>
					</TR>
				
				
END
			}
			print '</TABLE>';
		}
	} else {
		saySorry();
	}
	if (($numOfSolutions > 15) && (!$forceThin)) {
		$check=0;
		$rest=$end % $params{inst};
		# print bottom navigation bar if there are more than 15 sentences displayed
		&printNavigation(1) unless (($numOfSolutions == $end) && ($rest < 16));
	}

	# put restrictions into subcorpus table
	if (($firstQuery) && ($theRestrictions) && ($numOfSolutions)) {

		if (($writtenRes) && (!$spokenRes)) {
			$sqlQuery1 = "SELECT count(*) FROM headerInfo WHERE $writtenRes";
			if ($writtenRes=~m/(scgdom|sdeage|sdecla|sdesex|spolog|sporeg|alltyp=\'(1|2)|genre=\'([1-9]\'|1\d|2(0|1|2|3|4)))/) {
				$spowri = "spoken";
				$theSubcorpSelection = "last_spoken";
			} else {
				$spowri = "written";
				$theSubcorpSelection = "last_written";
			}
		} elsif ((!$writtenRes) && ($spokenRes)) {
			$sqlQuery1 = "SELECT count(*) FROM speakers WHERE $spokenRes";
			$spowri = "spoken";
			$theSubcorpSelection = "last_spoken";
		} else {
			$sqlQuery1 = "SELECT count(*) FROM speakers, headerInfo WHERE headerInfo.fname = speakers.filename and $writtenRes AND $spokenRes";
			$spowri = "wrispo";
			$theSubcorpSelection = "last_spoken";
		}

		$sqlQuery = "SELECT * FROM subcorpora WHERE username = '$username' and subcorpus = '$theSubcorpSelection'";
		$sth = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
		$sth->execute or bark("Can't execute $sqlQuery: " . $sth::errstr);
		$res=$sth->rows;


		if (($writtenRes) && (!$spokenRes)) {
			$sqlQuery = "SELECT fnum FROM headerInfo WHERE $writtenRes ORDER BY fnum";
		} elsif ((!$writtenRes) && ($spokenRes)) {
			$sqlQuery = "SELECT snum FROM speakers WHERE $spokenRes ORDER BY snum";
		} else {
			$sqlQuery = "SELECT snum FROM speakers, headerInfo WHERE headerInfo.fname = speakers.filename and $writtenRes AND $spokenRes ORDER BY snum";
		}
		$sth2 = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery:" . $bncHandle::errstr);
		$sth2->execute or bark("Can't execute $sqlQuery:" . $sth::errstr);
		$resArrayResult=$sth2->fetchall_arrayref;
		
		$allfiles = "";
		for $k ( 0 .. ($#{$resArrayResult}) ) {
			$theItem=$resArrayResult->[$k][0];
			$allfiles .= "·$theItem";
		}
		$allfiles=~s/\A·//;

		$sth = $bncHandle->prepare($sqlQuery1) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
		$sth->execute or bark("Can't execute $sqlQuery1: " . $sth::errstr);
		@rowArray=$sth->fetchrow_array;
		$numFiles=$rowArray[0];
		if ($res) {
			$sqlQuery = "UPDATE subcorpora SET fnums = '$allfiles', numwords = $numTotalWords, numfiles = $numFiles, spowri = '$spowri', textOrSpeaker = '$textOrSpeaker', metatextual = $metatextualQuote WHERE username = '$username' and subcorpus = '$theSubcorpSelection'";
		} else {
			$sqlQuery = "insert into subcorpora (subcorpus, username, fnums, numfiles, numwords, spowri, textOrSpeaker, metatextual) values ('$theSubcorpSelection', '$username', '$allfiles', $numFiles, $numTotalWords, '$spowri', '$textOrSpeaker', $metatextualQuote)";
		}
		$bncHandle->do($sqlQuery) or bark("Can't insert $sqlQuery: " . $bncHandle::errstr);
	}


	# print the end of html
	if ($forceThin) {

		$indexBut = '/' . $bwCGIalias . '/main.pl?chunk=1' . 
		'&inst='. $paramsEnc{inst} . 
		'&qname=' . $paramsEnc{qname} . 
		'&queryID=' . $paramsEnc{queryID} . 
		'&oldthMode=' . $paramsEnc{thMode} . 
		'&numOfFiles=' .  $paramsEnc{numOfFiles} . 
		'&theData=' .  $paramsEnc{theData} . 
		'&warned=' .  $paramsEnc{warned} . 
		'&numOfSolutions=' .  $paramsEnc{numOfSolutions} . 
		'&view=' .  $paramsEnc{view} . 
		'&theID=' .  $paramsEnc{theID} . 
		'&thMode=1' .  
		'&thin=' . $bwThinValue .
		'&max=INIT&urlTest=yes';

		print <<END;
		<SCRIPT><!--
		location.replace("$indexBut");
		//--></SCRIPT>
	
END
		$titleBar = &createTitle($params{thMode}, $theDataL, $numOfSolutions, $params{numOfFiles}, $listFiles, $numTotalWords, $numTotalWordsOrig, $params{subcorpus}, $theRestrictions, $timeTaken, $inCache, $numOfSpeakers);

		print <<END;
		<TABLE>
		<TR>
			<TD HEIGHT="26" COLSPAN="8" BGCOLOR="#CCCCFF">
				<P ALIGN="LEFT">$titleBar
			</TD>
		</TR>
		<TR>
		<TD>
		<br><B>For standard BNCweb users without a full license for the BNC, the display of query results is limited to a maximum of 
END
		print "$bwThinValue hits.</b><br>";
		print '<BR><A HREF="' . $indexBut . '"> [show ' . $bwThinValue . ' randomly thinned hits]</A><br>';

		print <<END;
		<br>If you enable JavaScript in your browser, this thinning process will be done automatically.
		
		</TD>
		</TR>
		</TABLE>
END
	
		&printFooter();

	} else {
		&printFooter();
	}
	#exit(0);
#}

# SUBROUTINES

## ***ADD***
# run CQP query with optional ((longest)) or ((all)) modifier
# usage: run_query_with_modifier($qName, $query);
sub run_query_with_modifier {
  my ($name, $query) = @_;
  if ($query =~ s/^\s*\({2}([A-Za-z]+)\){2}\s*//) {
    my $mode = lc($1);
    if ($mode eq "longest") {
      $CQP->exec("set MatchingStrategy longest");
    }
    elsif ($mode eq "all") {
      $CQP->exec("set MatchingStrategy traditional");
    }
    else {
      cqp_error_handler_full("<b>Syntax error</b>", 
                             "<code>(($mode))</code> is not a valid query modifier.");
    }
  }
  return $CQP->exec_query("$qName = $query");
}

sub solve {
	local($theData, $chunk, $inst, $qName, $lemmaScheme)=@_;
	local($query, $response, $numOfSolutions, $numOfFiles);
		
	if ($qName ne "INIT") {
		$CQP->exec("set DataDirectory '/$bwTempPath/'");
		$CQP->exec("$bwCorpus");
						
		($numOfSolutions) = $CQP->exec("size $qName");
				
		$qName = "INIT" unless $numOfSolutions;
		setParam("thin", "0") unless $numOfSolutions;
		
 		@lines = $CQP->exec("group $qName match text_id");	# list of documents with frequencies
 		$numOfFiles = @lines;
 		@lines = $CQP->exec("group $qName match u_who");
 		$numOfSpeakers = @lines;
		@stat = stat("/$bwTempPath/$bwCorpus:$qName");
		$fileSize = $stat[7];
	}

	# if new query
	if ($qName eq "INIT") {
		if ($params{recreate}) {
			# probably obsolete
			$sqlQuery = "SELECT query, thMode FROM categorize where queryID = '$params{recreate}'";
			$sth = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
			$sth->execute or bark("Can't execute $sqlQuery: ". $sth::errstr);
			@rowArray=$sth->fetchrow_array;
			$originalQuery = $rowArray[0];
			$originalThMode = $rowArray[1];
			
			$inCache = &checkCache($originalQuery, "", "", $originalThMode);
			
			if ($inCache) {
				$CQP->exec("set DataDirectory '/$bwTempPath/'");
				$CQP->exec("$bwCorpus");
				$qName = $inCache;
				($numOfSolutions) = $CQP->exec("size $qName");
			
			} else {
				qx{cp /$bwTempPath/$bwCorpus:$params{recreate} /$bwTempPath/$bwCorpus:$userCheck};
				$CQP->exec("set DataDirectory '/$bwTempPath/'");
				$CQP->exec("$bwCorpus");
										
				($numOfSolutions) = $CQP->exec("size $userCheck");
	
				@stat = stat("/$bwTempPath/$bwCorpus:$userCheck");
				$fileSize = $stat[7];
	
				$qName = $userCheck;
			}
		} else {	
			
		  ## ***DEL***
		  # if ($theData=~/\A###/) {
		  #   $CQP->exec("set ms longest");
		  # };

			$qName = $userCheck;
			my $tempFileName = $userCheck;
			my $tempfile = "/$bwTempPath/$tempFileName";
			my $tempfileMysql = "/$bwMySQLTempPath/$tempFileName";
			if (!$theRestrictions) {
				
				if ($params{qtype} eq "0") {					
					$inCache = &checkCache($theData, "", $qName);
					
					#$CQP->exec("define macro np(0) '[pos = \"(AV.|XX0)\"] [pos = \"(AJ.|CRD|DT0|ORD)\"] [pos = \"(N.*|ZZ0)\"]'");
					
          ## ***DEL***
          # $theData=~s/\A###//;
          # $CQP->exec_query("$qName = $theData") unless ($inCache);
          ## ***ADD***
					run_query_with_modifier($qName, $theData) unless ($inCache);
					#$CQP->exec("sort $qName randomize 42") unless ($inCache);
					$subcorpus = "no_subcorpus";
				} else {
					$decide = 0;
					
					
					if ($params{qtype} == 1) {
						$subcorpus = "(spowri=1)";
						$inCache = &checkCache($theData, $subcorpus, $qName);
						$sqlQuery = "SELECT beginPosition, endPosition INTO OUTFILE '$tempfileMysql' FROM headerInfo WHERE spowri = 1 ORDER BY beginPosition";
						setParam("subcorpus", "$subcorpus");
						$decide++;
					} elsif ($params{qtype} == 2) {
						$subcorpus = "(spowri=2)";
						$inCache = &checkCache($theData, $subcorpus, $qName);
						$sqlQuery = "SELECT beginPosition, endPosition INTO OUTFILE '$tempfileMysql' FROM headerInfo WHERE spowri = 2 ORDER BY beginPosition";
						setParam("subcorpus", "$subcorpus");
						$decide++;
					} else {
						($fnumList, $textOrSpeaker) = &subCorporaList($username, $params{qtype});
						if ($textOrSpeaker eq "text") {
							$sqlQuery = "SELECT beginPosition, endPosition INTO OUTFILE '$tempfileMysql' FROM headerInfo WHERE $fnumList ORDER BY beginPosition";
							$decide++;
						} else {
							$numberItems = &getSpokenPositions($fnumList, $tempfile);
							$CQP->exec("undump Subcorpus < '$tempfile'");
						}
						setParam("subcorpus", "$params{qtype}");
					}
	
					if (($decide) && (!$inCache)) {
						$sth = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
						$sth->execute or bark("Can't execute $sqlQuery: ". $sth::errstr);
						$numberItems = $sth->rows;
						&undump_file("Subcorpus", $tempfile, $numberItems);
					}
					unless ($inCache) {
						$CQP->exec("Subcorpus");
            ## ***DEL***
            # $theData=~s/\A###//;
            # $CQP->exec_query("$qName = $theData");
            ## ***ADD***
						run_query_with_modifier($qName, $theData);
					}
				}
			
			} else {
				($writtenRes, $spokenRes) = split(/##/, $theRestrictions);
				$decide = 0;
				$inCache = &checkCache($theData, $theRestrictions, $qName);
				if (($writtenRes) && (!$spokenRes)) {
					$sqlQuery = "SELECT beginPosition, endPosition INTO OUTFILE '$tempfileMysql' FROM headerInfo WHERE $writtenRes ORDER BY beginPosition";
					$subcorpus = $writtenRes;
					$decide++;
				} elsif ((!$writtenRes) && ($spokenRes)) {
					$numberItems = &getSpokenPositions($spokenRes, $tempfile);
					$subcorpus = $spokenRes;
				} else {
					$subcorpus = $writtenRes . " AND " . $spokenRes;
					$numberItems = &getSpokenPositions($subcorpus, $tempfile, "written");
				}
				
				if (($decide) && (!$inCache)) {
					$sth = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
					$sth->execute or bark("Can't execute $sqlQuery: ". $sth::errstr);
					if ($sth->rows) {
						&undump_file("Subcorpus", $tempfile, $sth->rows);
					} else {
						saySorry("no_files");
					}
	
				} else {
					$CQP->exec("undump Subcorpus < '$tempfile'") unless ($inCache);
				}
				unless ($inCache) {
					$CQP->exec("Subcorpus");
          ## ***DEL***
          # $theData=~s/\A###//;
          # $CQP->exec_query("$qName = $theData");
          ## ***ADD***
					run_query_with_modifier($qName, $theData);
				}
				setParam("subcorpus", "$subcorpus");
			}
			
			unlink("$tempfile") if -f "$tempfile";
			
			$CQP->exec("set DataDirectory '/$bwTempPath/'");
			$CQP->exec("$bwCorpus");
			unless ($inCache) {
				$CQP->exec("save $qName");
				
				@stat = stat("/$bwTempPath/$bwCorpus:$qName");
				$fileSize = $stat[7];
			} else {
				$qName = $inCache;
			}
			
			($numOfSolutions) = $CQP->exec("size $qName");
							
			@lines = $CQP->exec("group $qName match text_id");	# list of documents with frequencies
			$numOfFiles = @lines;
			@lines = $CQP->exec("group $qName match u_who");	
			$numOfSpeakers = @lines;
		}
		
	}	
 	$titleBar="has $numOfSolutions hits" if ($inst eq "count hits");

	$thinSelector='<OPTION>Thin...</OPTION>' unless ($params{thMode}=~m/##T\d#\d+\Z/);
	return($numOfSolutions, $qName, $numOfFiles, $inCache, $numOfSpeakers);
}


sub thin {

	# add something to enter things into savedQueries!!!
	# SH 8.5.2006
	my $thin = $params{thin};
	$thin =~ s/[\s,]+//g; 
	if ($thin =~ /^[0-9]+$/) {
		bark("Cannot thin down to $thin results: query has only $numOfSolutions matches")
			if $thin > $numOfSolutions and $params{thMode} !=3; # mode 3 is currently defunct ...
	}
	elsif ($thin =~ /^([0-9]+)\%$/) {
		bark("Thin percentage must be between 1\% and 100\% (value specified: $thin)")
			unless $0 < $1 and $1 <= 100;
	}
	else {
		bark("Invalid thin factor '$params{thin}': specify either a number or percentage (without decimal digits)");
	}

	setParam("thin", "$thin");
	$oldNum=$numOfSolutions;
	$qNameNew = $username . "_" . $theTime;

	$CQP->exec("set DataDirectory '/$bwTempPath/'");
	$CQP->exec("$bwCorpus");
	
	$CQP->exec("$qNameNew = $qName");
	$CQP->exec("randomize 42") if ($params{thMode} == 1);	
	$CQP->exec("reduce $qNameNew to $thin");

	$CQP->exec("save $qNameNew");
	@stat = stat("/$bwTempPath/$bwCorpus:$qNameNew");
	$fileSize = $stat[7];
	
	setParam("qname","$qNameNew");
	$qName = $qNameNew;
	
	($numOfSolutions) = $CQP->exec("size $qName");

	if ($params{oldthMode}) {
		$thMode = $params{oldthMode};
		$thMode = $thMode . "##T$params{thMode}#${numOfSolutions}";
		setParam("thMode", "$thMode");
		setParam("oldthMode", "");
	} else {
		# when do we get here??????
		setParam("thMode", "M${oldNum}#$params{numOfFiles}##T$params{thMode}#${numOfSolutions}");
	}
	
	return($numOfSolutions);
}

sub randomize {
	
	$qNameNew = $username . "_" . int(time);
	
	$CQP->exec("set DataDirectory '/$bwTempPath/'");
	$CQP->exec("$bwCorpus");

	
	$CQP->exec("$qNameNew = $qName");

	$CQP->exec("sort $qNameNew randomize 42");
	
	$CQP->exec("save $qNameNew");
	@stat = stat("/$bwTempPath/$bwCorpus:$qNameNew");
	$fileSize = $stat[7];
	
	setParam("qname","$qNameNew");
	$qName = $qNameNew;
	
	$thMode = $params{thMode};
	$thMode = $thMode . "##V#${numOfSolutions}";
	setParam("thMode", "$thMode");
	setParam("randomize", "");
}

sub unRandomize {
	
	$qNameNew = $username . "_" . int(time);
	
	$CQP->exec("set DataDirectory '/$bwTempPath/'");
	$CQP->exec("$bwCorpus");

	
	$CQP->exec("$qNameNew = $qName");

	$CQP->exec("sort $qNameNew");
	
	$CQP->exec("save $qNameNew");
	@stat = stat("/$bwTempPath/$bwCorpus:$qNameNew");
	$fileSize = $stat[7];
	
	setParam("qname","$qNameNew");
	$qName = $qNameNew;
	
	$thMode = $params{thMode};
	$thMode=~s/##V#\d+\Z//;
	setParam("thMode", "$thMode");
	setParam("unRandomize"," ");
}
		
sub createNavigationLinks {
	if ( ($params{inst} ne "show all") || (($numOfSolutions / $params{inst}) > 1))  {
		# set start and end s number
		$start = ($params{chunk} * $params{inst}) - ($params{inst});
		$end = (($params{chunk}+1) * $params{inst}) - ($params{inst});
		$end = $numOfSolutions if ($end > $numOfSolutions);
	} else {
		print "nshow all  $params{inst}<BR>";
		$start = 0;
		$end = $numOfSolutions;
	}
	$theDataTemp = $params{theData};
	setParam("theData", "$OriginaltheData");
	
	# print links to other pages
	if ( (($params{inst} ne "show all") && ($params{inst} ne "count hits")) || (($numOfSolutions / $params{inst}) > 1) ) {
		$div = ($numOfSolutions / $params{inst});
		$divInt = int($div);
		$divInt = $divInt + 1  if ($div > $divInt);
		setParam("max", "$divInt");
				
		$theLink = '<A HREF="/' . $bwCGIalias . '/' . $thisProg . '?XYZ2">';
		$link = "program=$paramsEnc{program}&textOrSpeaker=$paramsEnc{textOrSpeaker}&theData\=$paramsEnc{theData}&chunk=XXZ1&inst=$paramsEnc{inst}&max=$paramsEnc{max}&queryID=$paramsEnc{queryID}&run=$paramsEnc{run}&qname=$paramsEnc{qname}&thMode=$paramsEnc{thMode}&thin=$paramsEnc{thin}&qtype=$paramsEnc{qtype}&view=$paramsEnc{view}&view2=$paramsEnc{view2}&word=$paramsEnc{word}&SQL=$paramsEnc{SQL}&dbname=$paramsEnc{dbname}&ot=$paramsEnc{ot}&exclude=$paramsEnc{exclude}&letter=$paramsEnc{letter}&tag=$paramsEnc{tag}&numOfFiles=$paramsEnc{numOfFiles}&categorize=$paramsEnc{categorize}&subcorpus=$paramsEnc{subcorpus}&listFiles=$paramsEnc{listFiles}&theID=$paramsEnc{theID}&urlTest=yes";
		$theLink =~ s/XYZ2/$link/o;
		$startFont="<FONT SIZE=3 FACE=\"Arial, Helvetica\"><B>";
		$endFont="</B></FONT>";
		if (($params{chunk} -1) >= 1) {
			$theLink1 = $theLink;
			$i = $params{chunk} - 1;
			$theLink1 =~ s/XXZ1/$i/;
			$navBar.= "<TD NOWRAP WIDTH=\"3%\" BGCOLOR=\"#DDDDDD\"><P ALIGN=\"CENTER\">${theLink1}$startFont&nbsp;&lt;&lt;&nbsp;$endFont</A></TD>\n";
		} else {
			$navBar.= "<TD NOWRAP WIDTH=\"3%\" BGCOLOR=\"#DDDDDD\"><P ALIGN=\"CENTER\">$startFont&nbsp;&lt;&lt;&nbsp;$endFont</TD>\n";
		}
		if (($params{chunk} +1) <= $divInt) {
			$theLink1 = $theLink;
			$i = $params{chunk} +1;
			$theLink1 =~ s/XXZ1/$i/;
			$navBar.= "<TD NOWRAP WIDTH=\"3%\" BGCOLOR=\"#DDDDDD\"><P ALIGN=\"CENTER\">${theLink1}$startFont&nbsp;&gt;&gt;&nbsp;$endFont</A></TD>\n";

		} else {
			$navBar.= "<TD NOWRAP WIDTH=\"3%\" BGCOLOR=\"#DDDDDD\"><P ALIGN=\"CENTER\">$startFont&nbsp;&gt;&gt;&nbsp;$endFont</TD>\n";
		}

		if ($params{chunk} != 1) {
			$theLink1 = $theLink;
			$theLink1 =~ s/XXZ1/1/;
			$navBar = "<TD NOWRAP WIDTH=\"3%\" BGCOLOR=\"#DDDDDD\"><P ALIGN=\"CENTER\">${theLink1}$startFont&nbsp;I&lt;&nbsp;$endFont</A></TD>$navBar\n";
		} else {
			$navBar = "<TD NOWRAP WIDTH=\"3%\" BGCOLOR=\"#DDDDDD\"><P ALIGN=\"CENTER\">$startFont&nbsp;I&lt;&nbsp;$endFont</TD>$navBar\n";
		}

		if ($params{chunk} < $divInt) {
			$theLink1 = $theLink;
			$i = $params{chunk} +1;
			$theLink1 =~ s/XXZ1/$divInt/;
			$navBar.= "<TD NOWRAP WIDTH=\"3%\" BGCOLOR=\"#DDDDDD\"><P ALIGN=\"CENTER\">${theLink1}$startFont&nbsp;&gt;I&nbsp;$endFont</A></TD>\n";
		} else {
			$navBar.= "<TD NOWRAP WIDTH=\"3%\" BGCOLOR=\"#DDDDDD\"><P ALIGN=\"CENTER\">$startFont&nbsp;&gt;I&nbsp;$endFont</TD>\n";
		}
		
		$pageInd = "   Page $params{chunk} \/ $divInt";
	}
	setParam("theData", "$theDataTemp");
}

sub printNavigation {
	$bottom=@_[0];

	
	$theData2=&encodeForm($OriginaltheData);
		
	if ($params{timeTaken}) {
		$timeTaken = $params{timeTaken};
		setParam("timeTaken","");
	}
	print <<END;

		<TABLE BORDER="0" CELLPADDING="2" CELLSPACING="2" WIDTH="100%">
END

	unless ($bottom) {
		$titleBar = &createTitle($params{thMode}, $theDataL, $numOfSolutions, $params{numOfFiles}, $listFiles, $numTotalWords, $numTotalWordsOrig, $params{subcorpus}, $theRestrictions, $timeTaken, $inCache, $numOfSpeakers);
		
		print <<END;
		<TR>
			<TD HEIGHT="26" COLSPAN="8" BGCOLOR="#CCCCFF">
				<P ALIGN="LEFT">$titleBar
			</TD>
		</TR>
END
	}
	
	if ($params{inst} eq "count hits") {
		print "</TABLE>";
		&printFooter();
		return(0);
	}
	print <<END;	
		<TR>
			$navBar
			<FORM ACTION="/$bwCGIalias/${thisProg}" METHOD="GET">
			<TD WIDTH="15%" BGCOLOR="#DDDDDD" NOWRAP>
				<INPUT TYPE="HIDDEN" NAME="theData" SIZE="-1" VALUE="$theData2">
				<INPUT TYPE="SUBMIT" VALUE="Show Page:">
				<INPUT TYPE="text" NAME="chunk" VALUE="1" SIZE=8>
				<INPUT TYPE="hidden" NAME="inst" VALUE="$params{inst}">
				<INPUT TYPE="hidden" NAME="max" VALUE="$params{max}">
				<INPUT TYPE="hidden" NAME="qname" VALUE="$params{qname}">
				<INPUT TYPE="hidden" NAME="queryID" VALUE="$params{queryID}">
				<INPUT TYPE="hidden" NAME="thMode" VALUE="$params{thMode}">
				<INPUT TYPE="hidden" NAME="thin" VALUE="$params{thin}">
				<INPUT TYPE="hidden" NAME="qtype" VALUE="0">
				<INPUT TYPE="hidden" NAME="view" VALUE="$params{view}">
				<INPUT TYPE="hidden" NAME="view2" VALUE="$params{view2}">
				<INPUT TYPE="hidden" NAME="program" VALUE="$params{program}">
				<INPUT TYPE="hidden" NAME="SQL" VALUE="$params{SQL}">
				<INPUT TYPE="hidden" NAME="word" VALUE="$params{word}">
				<INPUT TYPE="hidden" NAME="textOrSpeaker" VALUE="$params{textOrSpeaker}">
				<INPUT TYPE="hidden" NAME="dbname" VALUE="$params{dbname}">
				<INPUT TYPE="hidden" NAME="ot" VALUE="$params{ot}">
				<INPUT TYPE="hidden" NAME="exclude" VALUE="$params{exclude}">
				<INPUT TYPE="hidden" NAME="letter" VALUE="$params{letter}">
				<INPUT TYPE="hidden" NAME="tag" VALUE="$params{tag}">
				<INPUT TYPE="hidden" NAME="numOfFiles" VALUE="$params{numOfFiles}">
				<INPUT TYPE="hidden" NAME="numOfSolutions" VALUE="$numOfSolutions">
				<INPUT TYPE="hidden" NAME="categorize" VALUE="$params{categorize}">
				<INPUT TYPE="hidden" NAME="run" VALUE="$params{run}">
				<INPUT TYPE="hidden" NAME="subcorpus" VALUE="$params{subcorpus}">
				<INPUT TYPE="hidden" NAME="listFiles" VALUE="$params{listFiles}">
				<INPUT TYPE="hidden" NAME="theID" VALUE="$params{theID}">
				<INPUT TYPE="hidden" NAME="urlTest" VALUE="yes">
			</TD>
			</FORM>
END
	if (!$listFiles) {
		print <<END;
			<FORM ACTION="/$bwCGIalias/${thisProg}" METHOD=GET>
			<TD WIDTH="15%"  NOWRAP BGCOLOR="#DDDDDD" ALIGN="MIDDLE">
				<INPUT TYPE="HIDDEN" NAME="theData" SIZE="-1" VALUE="$theData2">
				<INPUT TYPE="SUBMIT" VALUE="$reverseBut">
				<INPUT TYPE="hidden" NAME="chunk" VALUE="$params{chunk}">
				<INPUT TYPE="hidden" NAME="inst" VALUE="$params{inst}">
				<INPUT TYPE="hidden" NAME="max" VALUE="$params{max}">
				<INPUT TYPE="hidden" NAME="qname" VALUE="$params{qname}">
				<INPUT TYPE="hidden" NAME="queryID" VALUE="$params{queryID}">
				<INPUT TYPE="hidden" NAME="thMode" VALUE="$params{thMode}">
				<INPUT TYPE="hidden" NAME="thin" VALUE="$params{thin}">
				<INPUT TYPE="hidden" NAME="qtype" VALUE="0">
				<INPUT TYPE="hidden" NAME="view" VALUE="$reverseView">
				<INPUT TYPE="hidden" NAME="view2" VALUE="$params{view2}">
				<INPUT TYPE="hidden" NAME="program" VALUE="$params{program}">
				<INPUT TYPE="hidden" NAME="SQL" VALUE="$params{SQL}">
				<INPUT TYPE="hidden" NAME="word" VALUE="$params{word}">
				<INPUT TYPE="hidden" NAME="dbname" VALUE="$params{dbname}">
				<INPUT TYPE="hidden" NAME="distance" VALUE="$distance">
				<INPUT TYPE="hidden" NAME="ot" VALUE="$params{ot}">
				<INPUT TYPE="hidden" NAME="exclude" VALUE="$params{exclude}">
				<INPUT TYPE="hidden" NAME="letter" VALUE="$params{letter}">
				<INPUT TYPE="hidden" NAME="tag" VALUE="$params{tag}">
				<INPUT TYPE="hidden" NAME="numOfFiles" VALUE="$params{numOfFiles}">
				<INPUT TYPE="hidden" NAME="numOfSolutions" VALUE="$numOfSolutions">
				<INPUT TYPE="hidden" NAME="categorize" VALUE="$params{categorize}">
				<INPUT TYPE="hidden" NAME="run" VALUE="$params{run}">
				<INPUT TYPE="hidden" NAME="subcorpus" VALUE="$params{subcorpus}">
				<INPUT TYPE="hidden" NAME="theID" VALUE="$params{theID}">
				<INPUT TYPE="hidden" NAME="urlTest" VALUE="yes">
			</TD>
			</FORM>
END

		if ($params{categorize} ne "yes") {
			print <<END;
			<FORM ACTION="/$bwCGIalias/${thisProg}" METHOD=GET>
			<TD WIDTH="20%"  NOWRAP BGCOLOR="#DDDDDD" ALIGN="MIDDLE">
				<INPUT TYPE="HIDDEN" NAME="theData" SIZE="-1" VALUE="$theData2">
				<INPUT TYPE="SUBMIT" VALUE="$reverseBut2">
				<INPUT TYPE="hidden" NAME="chunk" VALUE="$params{chunk}">
				<INPUT TYPE="hidden" NAME="inst" VALUE="$params{inst}">
				<INPUT TYPE="hidden" NAME="max" VALUE="$params{max}">
				<INPUT TYPE="hidden" NAME="qname" VALUE="$params{qname}">
				<INPUT TYPE="hidden" NAME="queryID" VALUE="$params{queryID}">
				<INPUT TYPE="hidden" NAME="thMode" VALUE="$params{thMode}">
				<INPUT TYPE="hidden" NAME="thin" VALUE="$params{thin}">
				<INPUT TYPE="hidden" NAME="qtype" VALUE="0">
				<INPUT TYPE="hidden" NAME="view" VALUE="$params{view}">
				<INPUT TYPE="hidden" NAME="randomize" VALUE="$reverseView2">
				<INPUT TYPE="hidden" NAME="program" VALUE="$params{program}">
				<INPUT TYPE="hidden" NAME="SQL" VALUE="$params{SQL}">
				<INPUT TYPE="hidden" NAME="word" VALUE="$params{word}">
				<INPUT TYPE="hidden" NAME="dbname" VALUE="$params{dbname}">
				<INPUT TYPE="hidden" NAME="distance" VALUE="$distance">
				<INPUT TYPE="hidden" NAME="ot" VALUE="$params{ot}">
				<INPUT TYPE="hidden" NAME="exclude" VALUE="$params{exclude}">
				<INPUT TYPE="hidden" NAME="letter" VALUE="$params{letter}">
				<INPUT TYPE="hidden" NAME="tag" VALUE="$params{tag}">
				<INPUT TYPE="hidden" NAME="numOfFiles" VALUE="$params{numOfFiles}">
				<INPUT TYPE="hidden" NAME="numOfSolutions" VALUE="$numOfSolutions">
				<INPUT TYPE="hidden" NAME="categorize" VALUE="$params{categorize}">
				<INPUT TYPE="hidden" NAME="run" VALUE="$params{run}">
				<INPUT TYPE="hidden" NAME="subcorpus" VALUE="$params{subcorpus}">
				<INPUT TYPE="hidden" NAME="theID" VALUE="$params{theID}">
				<INPUT TYPE="hidden" NAME="urlTest" VALUE="yes">
			</TD>
			</FORM>
END
		} else {
			print <<END;
			<TD WIDTH="20%"  NOWRAP BGCOLOR="#DDDDDD" ALIGN="MIDDLE">&nbsp;</TD>
END
		}
	}
	if ($params{categorize} ne "yes") {
		print <<END;
			<FORM ACTION="/$bwCGIalias/dlogs.pl" METHOD=GET>
			<TD NOWRAP BGCOLOR="#DDDDDD">
				
				<SELECT NAME="selected">
END
		
		$categorizeOption="<OPTION>Categorize hits...</OPTION>" unless ($params{categorize} eq "yes");
		
		print "<OPTION SELECTED>New Query</OPTION>";
		
		if (!$listFiles) {
			print $thinSelector;
			
			if ($params{program} eq "sort") {
				print "<OPTION VALUE=\"frequency\">Frequency breakdown</OPTION>";
			} else {
				print "<OPTION>Frequency breakdown</OPTION>";
			}
			print <<END;
				<OPTION>Distribution</OPTION>
				<OPTION>Sort</OPTION>
				<OPTION>Collocations...</OPTION>
				<OPTION>Download...</OPTION>
				$categorizeOption
				<OPTION>Save current set of hits...</OPTION>
END
	
		
		}
		print <<END;				


					</SELECT>
					<INPUT TYPE="hidden" NAME="inst" VALUE="$params{inst}">
					<INPUT TYPE="hidden" NAME="max" VALUE="$params{max}">
					<INPUT TYPE="hidden" NAME="chunk" VALUE="$params{chunk}">
					<INPUT TYPE="hidden" NAME="qname" VALUE="$params{qname}">
					<INPUT TYPE="hidden" NAME="queryID" VALUE="$params{queryID}">
					<INPUT TYPE="hidden" NAME="thMode" VALUE="$params{thMode}">
					<INPUT TYPE="hidden" NAME="thin" VALUE="$params{thin}">
					<INPUT TYPE="hidden" NAME="theData" VALUE="$theData2">
					<INPUT TYPE="hidden" NAME="warned" VALUE="0">
					<INPUT TYPE="hidden" NAME="numOfSolutions" VALUE="$numOfSolutions">
					<INPUT TYPE="hidden" NAME="numOfFiles" VALUE="$numOfFiles">
					<INPUT TYPE="hidden" NAME="view" VALUE="$params{view}">
					<INPUT TYPE="hidden" NAME="dbname" VALUE="$params{dbname}">
					<INPUT TYPE="hidden" NAME="SQL" VALUE="$params{SQL}">
					<INPUT TYPE="hidden" NAME="letter" VALUE="$params{letter}">
					<INPUT TYPE="hidden" NAME="tag" VALUE="$params{tag}">
					<INPUT TYPE="hidden" NAME="ot" VALUE="$params{ot}">
					<INPUT TYPE="hidden" NAME="display" VALUE="word">
					<INPUT TYPE="hidden" NAME="exclude" VALUE="$params{exclude}">
					<INPUT TYPE="hidden" NAME="program" VALUE="$params{program}">
					<INPUT TYPE="hidden" NAME="run" VALUE="$params{run}">
					<INPUT TYPE="hidden" NAME="theID" VALUE="$params{theID}">
					<INPUT TYPE="hidden" NAME="urlTest" VALUE="yes">
					<INPUT TYPE="SUBMIT" VALUE="Go!">
					
				</TD>
			</FORM>
			
END
} else {
# 		print <<END;
# 			<FORM ACTION="/$bwCGIalias/dlogs.pl" METHOD=GET>
# 			<TD NOWRAP BGCOLOR="#DDDDDD">
# 				<SELECT NAME="selected">
# 					<OPTION SELECTED>New Query</OPTION>
# 				</SELECT>
# 				<INPUT TYPE="hidden" NAME="urlTest" VALUE="yes">
# 				<INPUT TYPE="SUBMIT" VALUE="Go!">
# 				
# 				</FORM>
# 					
# END
		print <<END;
			<TD NOWRAP BGCOLOR="#DDDDDD">
				&nbsp;
			</TD>					
END

		
}
if ($listFiles) {
	if ($bottom) {
		print "<TD BGCOLOR=\"#DDDDDD\">&nbsp;</TD>";
	} else {
		# need a form to enter choice of files for subcorpora
		
		if ($typeOfSubcorpus eq "written") {
			$selectList = " and textOrSpeaker = 'text'";
		} else {
			$selectList = " and textOrSpeaker = 'speaker'";
		}
		
		$subcorpusList="<OPTION SELECTED VALUE=\"new\">New subcorpus\n";
		$sqlQuery = "SELECT subcorpus FROM subcorpora where username = '$username' $selectList";
		$sth2 = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery:" . $bncHandle::errstr);
		$sth2->execute or bark("Can't execute $sqlQuery:" . $sth::errstr);
		$resArrayResult=$sth2->fetchall_arrayref;

		for $k ( 0 .. ($#{$resArrayResult}) ) {
			$theCorpus=$resArrayResult->[$k][0];
			$subcorpusList .= "<OPTION VALUE=\"$theCorpus\">$theCorpus\n" unless ($theCorpus=~m/\Alast_(written|spoken)\Z/);
		}
		$subcorpus1 = $subcorpus;
		$subcorpus1=~s/\"/\'/g;
	
	
		print <<END;
		<TD WIDTH="20%"  NOWRAP BGCOLOR="#DDDDDD">
			<FORM ACTION="/$bwCGIalias/subcorpAdmin.pl" METHOD="GET">
			<SELECT NAME="subcorpus">
				$subcorpusList
			</SELECT>
			<INPUT TYPE="HIDDEN" NAME="metatextual" VALUE="$metatextualRestr">
			<INPUT TYPE="HIDDEN" NAME="spowri" VALUE="$typeOfSubcorpus">
			<INPUT TYPE="HIDDEN" NAME="textOrSpeaker" VALUE="$params{textOrSpeaker}">
			<INPUT TYPE="HIDDEN" NAME="username" VALUE="$username">
			<INPUT TYPE="SUBMIT" VALUE="Add">
			&nbsp;include all<INPUT TYPE="CHECKBOX" NAME="complete" VALUE="$subcorpus1">
		</TD>
END
	}
}
print "</TR>";

	if ($params{program} eq "sort") {
		$selected1{$params{letter}}="SELECTED";
		$selected1{all}="SELECTED" if (!$params{letter});
		if ($params{ot}=~m/#/) {
			$selected2{refnum}="SELECTED";
			$refnumSelect = $params{ot};
		} else {
			$selected2{$params{ot}}="SELECTED";
			$refnumSelect = "refnum#" . $params{ot};
		}
		
		if ($params{exclude} eq "yes") {
			$checked{yes} = "CHECKED";
		} else {
			$checked{yes} = "";
		}
		
		print <<END;
			<TR BGCOLOR="#CCCCCC">
				<TD COLSPAN=4 NOWRAP>
					<FORM ACTION="/$bwCGIalias/${thisProg}" METHOD="GET">
					<INPUT TYPE="hidden" NAME="program" VALUE="$params{program}">
					<INPUT TYPE="hidden" NAME="theData" VALUE="$theData2">
					<INPUT TYPE="hidden" NAME="dbname" VALUE="$params{dbname}">
					<INPUT TYPE="hidden" NAME="chunk" VALUE="1">
					<INPUT TYPE="hidden" NAME="inst" VALUE="$params{inst}">
					<INPUT TYPE="hidden" NAME="max" VALUE="$params{max}">
					<INPUT TYPE="hidden" NAME="qname" VALUE="$params{qname}">
					<INPUT TYPE="hidden" NAME="queryID" VALUE="$params{queryID}">
					<INPUT TYPE="hidden" NAME="view" VALUE="$params{view}">
					<INPUT TYPE="hidden" NAME="thMode" VALUE="$params{thMode}">
					<INPUT TYPE="hidden" NAME="categorize" VALUE="$params{categorize}">
					<INPUT TYPE="hidden" NAME="theID" VALUE="$params{theID}">
					&nbsp;<b>Sort parameters:</B>
				</TD>
				<TD COLSPAN=1 NOWRAP>
					&nbsp;Position: 
					<SELECT NAME="ot">
						<OPTION $selected2{before5} VALUE="before5">5 Left
						<OPTION $selected2{before4} VALUE="before4">4 Left
						<OPTION $selected2{before3} VALUE="before3">3 Left
						<OPTION $selected2{before2} VALUE="before2">2 Left
						<OPTION $selected2{before1} VALUE="before1">1 Left
						<OPTION $selected2{node} VALUE="node">node
						<OPTION $selected2{after1}  VALUE="after1">1 Right
						<OPTION $selected2{after2} VALUE="after2">2 Right
						<OPTION $selected2{after3} VALUE="after3">3 Right
						<OPTION $selected2{after4} VALUE="after4">4 Right
						<OPTION $selected2{after5} VALUE="after5">5 Right
					</SELECT>
					<INPUT TYPE="hidden" NAME="changeSort" VALUE="yes">
				</TD>				
				<TD COLSPAN=1 NOWRAP>
	
					&nbsp;Tag restriction:
					<SELECT NAME="tag">
						<OPTION $selected{nothing} VALUE="" > no restrictions
						<OPTION $selected{'VERB'} VALUE="VERB"> any verb
						<OPTION $selected{'SUBST'} VALUE="SUBST"> any noun
						<OPTION $selected{'ADJ'} VALUE="ADJ"> any adjective
						<OPTION $selected{'ADV'} VALUE="ADV"> any adverb
						<OPTION $selected{'ART'} VALUE="ART"> any article
						<OPTION $selected{'CONJ'} VALUE="CONJ"> any conjunction
						<OPTION $selected{'PREP'} VALUE="PREP"> any preposition
						<OPTION $selected{'PRON'} VALUE="PRON"> any pronoun
						<OPTION $selected{'INTERJ'} VALUE="INTERJ"> any interjection
						<OPTION $selected{'STOP'} VALUE="STOP"> any punctuation
						<OPTION $selected{'AJ0'}>AJ0
						<OPTION $selected{'AJC'}>AJC
						<OPTION $selected{'AJS'}>AJS
						<OPTION $selected{'AT0'}>AT0
						<OPTION $selected{'AV0'}>AV0
						<OPTION $selected{'AVP'}>AVP
						<OPTION $selected{'AVQ'}>AVQ
						<OPTION $selected{'CJC'}>CJC
						<OPTION $selected{'CJS'}>CJS
						<OPTION $selected{'CJT'}>CJT
						<OPTION $selected{'CRD'}>CRD
						<OPTION $selected{'DPS'}>DPS
						<OPTION $selected{'DT0'}>DT0
						<OPTION $selected{'DTQ'}>DTQ
						<OPTION $selected{'EX0'}>EX0
						<OPTION $selected{'ITJ'}>ITJ
						<OPTION $selected{'NN0'}>NN0
						<OPTION $selected{'NN1'}>NN1
						<OPTION $selected{'NN2'}>NN2
						<OPTION $selected{'NP0'}>NP0
						<OPTION $selected{'ORD'}>ORD
						<OPTION $selected{'PNI'}>PNI
						<OPTION $selected{'PNP'}>PNP
						<OPTION $selected{'PNQ'}>PNQ
						<OPTION $selected{'PNX'}>PNX
						<OPTION $selected{'POS'}>POS
						<OPTION $selected{'PRF'}>PRF
						<OPTION $selected{'PRP'}>PRP
						<OPTION $selected{'TO0'}>TO0
						<OPTION $selected{'UNC'}>UNC
						<OPTION $selected{'VBB'}>VBB
						<OPTION $selected{'VBD'}>VBD
						<OPTION $selected{'VBG'}>VBG
						<OPTION $selected{'VBI'}>VBI
						<OPTION $selected{'VBN'}>VBN
						<OPTION $selected{'VBZ'}>VBZ
						<OPTION $selected{'VDB'}>VDB
						<OPTION $selected{'VDD'}>VDD
						<OPTION $selected{'VDG'}>VDG
						<OPTION $selected{'VDI'}>VDI
						<OPTION $selected{'VDN'}>VDN
						<OPTION $selected{'VDZ'}>VDZ
						<OPTION $selected{'VHB'}>VHB
						<OPTION $selected{'VHD'}>VHD
						<OPTION $selected{'VHG'}>VHG
						<OPTION $selected{'VHI'}>VHI
						<OPTION $selected{'VHN'}>VHN
						<OPTION $selected{'VHZ'}>VHZ
						<OPTION $selected{'VM0'}>VM0
						<OPTION $selected{'VVB'}>VVB
						<OPTION $selected{'VVD'}>VVD
						<OPTION $selected{'VVG'}>VVG
						<OPTION $selected{'VVI'}>VVI
						<OPTION $selected{'VVN'}>VVN
						<OPTION $selected{'VVZ'}>VVZ
						<OPTION $selected{'XX0'}>XX0
						<OPTION $selected{'ZZ0'}>ZZ0
						<OPTION $selected{'AJ0-AV0'}>AJ0-AV0
						<OPTION $selected{'AJ0-NN1'}>AJ0-NN1
						<OPTION $selected{'AJ0-VVD'}>AJ0-VVD
						<OPTION $selected{'AJ0-VVG'}>AJ0-VVG
						<OPTION $selected{'AJ0-VVN'}>AJ0-VVN
						<OPTION $selected{'AV0-AJ0'}>AV0-AJ0
						<OPTION $selected{'AVP-PRP'}>AVP-PRP
						<OPTION $selected{'AVQ-CJS'}>AVQ-CJS
						<OPTION $selected{'CJS-AVQ'}>CJS-AVQ
						<OPTION $selected{'CJS-PRP'}>CJS-PRP
						<OPTION $selected{'CJT-DT0'}>CJT-DT0
						<OPTION $selected{'CRD-PNI'}>CRD-PNI
						<OPTION $selected{'DT0-CJT'}>DT0-CJT
						<OPTION $selected{'NN1-AJ0'}>NN1-AJ0
						<OPTION $selected{'NN1-NP0'}>NN1-NP0
						<OPTION $selected{'NN1-VVB'}>NN1-VVB
						<OPTION $selected{'NN1-VVG'}>NN1-VVG
						<OPTION $selected{'NN2-VVZ'}>NN2-VVZ
						<OPTION $selected{'NP0-NN1'}>NP0-NN1
						<OPTION $selected{'PNI-CRD'}>PNI-CRD
						<OPTION $selected{'PRP-AVP'}>PRP-AVP
						<OPTION $selected{'PRP-CJS'}>PRP-CJS
						<OPTION $selected{'VVB-NN1'}>VVB-NN1
						<OPTION $selected{'VVD-AJ0'}>VVD-AJ0
						<OPTION $selected{'VVD-VVN'}>VVD-VVN
						<OPTION $selected{'VVG-AJ0'}>VVG-AJ0
						<OPTION $selected{'VVG-NN1'}>VVG-NN1
						<OPTION $selected{'VVN-AJ0'}>VVN-AJ0
						<OPTION $selected{'VVN-VVD'}>VVN-VVD
						<OPTION $selected{'VVZ-NN2'}>VVZ-NN2
						<OPTION $selected{'PUL'}>PUL
						<OPTION $selected{'PUN'}>PUN
						<OPTION $selected{'PUQ'}>PUQ
						<OPTION $selected{'PUR'}>PUR
					</SELECT>
					<INPUT TYPE="CHECKBOX" NAME="exclude" VALUE="yes" $checked{yes}> exclude

				</TD>
				<TD COLSPAN="1" NOWRAP>	
					&nbsp;Starting with letter:
					
					<SELECT NAME="letter">
						<OPTION $selected1{all} VALUE="">all
						<OPTION $selected1{A}>A
						<OPTION $selected1{B}>B
						<OPTION $selected1{C}>C
						<OPTION $selected1{D}>D
						<OPTION $selected1{E}>E
						<OPTION $selected1{F}>F
						<OPTION $selected1{G}>G
						<OPTION $selected1{H}>H
						<OPTION $selected1{I}>I
						<OPTION $selected1{J}>J
						<OPTION $selected1{K}>K
						<OPTION $selected1{L}>L
						<OPTION $selected1{M}>M
						<OPTION $selected1{N}>N
						<OPTION $selected1{O}>O
						<OPTION $selected1{P}>P
						<OPTION $selected1{Q}>Q
						<OPTION $selected1{R}>R
						<OPTION $selected1{S}>S
						<OPTION $selected1{T}>T
						<OPTION $selected1{U}>U
						<OPTION $selected1{V}>V
						<OPTION $selected1{W}>W
						<OPTION $selected1{X}>X
						<OPTION $selected1{Y}>Y
						<OPTION $selected1{Z}>Z
					</SELECT>
				</TD>

				<TD>
					<INPUT TYPE="hidden" NAME="urlTest" VALUE="yes">
					<INPUT TYPE="submit" VALUE="Submit">
				</TD>
			</FORM>
		</TR>
	</TABLE>
END

	} else {
		print "</TABLE>";
	}
}

sub printIt {

	# post-process s-units from CQP for display
	local($kwic_lc, $kwic_match, $kwic_rc, $lineIndicator) = @_;
	#local($link2);
	
#	$kwic_match=~s/\A<//;
#	$kwic_match=~s/>\Z//;

	$hitCount=$lineIndicator;
	$lineIndicator++;
	
	local ($match, $matchend, $target, $keyword) = @{$table[$i]}; # corpus positions of query anchors (see CQP tutorial)

    $text = $TEXT_ID->cpos2str($match);	# use direct corpus access to obtain meta-information
    $u_who = $U_WHO->cpos2str($match);		# returns undef when not in <u>..</u> region
    $num = $S_N->cpos2str($match);		# sentence number within document
    
    ## obtaining the token offset within a sentence is a little more complicated
    $s_idx = $S->cpos2struc($match);
    ($match_start, $match_end) = $S->struc2cpos($s_idx);
    $token_offset = $match - $match_start;		# 0 = first token, 1 = second token, etc.
	
	#warn $kwic_match;
	
	#$kwic_lc=~s/\/\[ \]\//\/\[\xA0\]\//g;
	#$kwic_match=~s/\/\[ \]\//\/\[\xA0\]\//g;
	#$kwic_rc=~s/\/\[ \]\//\/\[\xA0\]\//g;
	
	$kwic_rc =~s/\A //;
	$kwic_lc =~s/\A //;
	$kwic_match =~s/\A //;
		
	@lc = split(/ /, $kwic_lc);
	@rc = split(/ /, $kwic_rc);
	@node = split(/ /, $kwic_match);
	
	$lcCount = @lc;
	$rcCount = @rc;
	$nodeCount = @node;


	if ($params{ot}=~m/before(\d)/) {
		$thePos = -$1;
	} elsif ($params{ot}=~m/after(\d)/) {
		$thePos = $1;
	} elsif ($colDist) {
		$thePos = $colDist;
	} else {
		$thePos = "";
	}
		
	# left context
	$kwic_lc = "";
	for ($l = 1; $l <= $lcCount; $l++) {
		$whole = $lc[-$l];
		($word, $space, $tag_before, $tag_after) = split(/\/\/\x{A0}/, $whole);
		$word=~s/\x{A0}/ /g;
		$tag_before=~s/\x{A0}/ /g;
		$tag_after=~s/\x{A0}/ /g;

		$showTag="";
		if ($tag_after=~m/<(pause[^\/]*)\/>/) {
			$showTag = " [$1]";
		}  elsif ($tag_after=~m/<\/trunc>/) {
 			$showTag = "-- ";
 		}
				
		$word=~m/\A(.*)\/(.*?)\/(w|c|x)\Z/;
		$word = $1;
		$tag = $2;
		$attribute = $3;
		if ($space) {
			$space = " ";
		} else {
			$space = "";
		}
		
		if ($thePos == -$l) {
			if ($params{tag}) {
				$kwic_lc = "ÏBå" . $word . "_$tag" . "Ï\/Bå" . $showTag . $space . $kwic_lc;
			} else {
				$kwic_lc = "ÏBå" . $word . "º_$tag°" . "Ï\/Bå" . $showTag . $space . $kwic_lc;
			}
		} else {
			$kwic_lc = $word . "º_$tag°" . $anchors . $showTag . $space . $kwic_lc;
		}
	}
	# right context
	$kwic_rc = "";
	for ($l = 1; $l <= $rcCount; $l++) {
		$whole = $rc[$l-1];
		($word, $space, $tag_before, $tag_after) = split(/\/\/\x{A0}/, $whole);

		$word=~s/\x{A0}/ /g;
		$tag_before=~s/\x{A0}/ /g;
		$tag_after=~s/\x{A0}/ /g;

		$showTag="";
		if ($tag_after=~m/<(pause[^\/]*)\/>/) {
			$showTag = " [$1]";
		}  elsif ($tag_after=~m/<\/trunc>/) {
 			$showTag = "-- ";
 		}

		
		$word=~m/\A(.*)\/(.*?)\/(w|c|x)\Z/;
		$word = $1;
		$tag = $2;
		$attribute = $3;
		
		if ($space) {
			$space = " ";
		} else {
			$space = "";
		}

		if ($thePos == $l) {
			if ($params{tag}) {
				$kwic_rc = $kwic_rc . "ÏBå" . $word . "_$tag" . "Ï\/Bå" . $showTag . $space;
			} else {
				$kwic_rc = $kwic_rc . "ÏBå" . $word . "º_$tag°" . "Ï\/Bå" . $showTag . $space;
			}
		} else {
			$kwic_rc = $kwic_rc . $word . "º_$tag°" . $showTag . $space;
		}

	}
	# node
	$kwic_match = "";
	for ($l = 1; $l <= $nodeCount; $l++) {
		$whole = $node[$l-1];
		($word, $space, $tag_before, $tag_after) = split(/\/\/\x{A0}/, $whole);

		$word=~s/\x{A0}/ /g;
		$tag_before=~s/\x{A0}/ /g;
		$tag_after=~s/\x{A0}/ /g;


		$showTagBefore="";
		if (($tag_before=~m/<s n=\"(\d+)\"/) && ($l > 1)) {
			$showTagBefore = "<span style=\"font-weight:normal; text-decoration:none; color:black;\">[$text " . $1 . "]</span> " unless (!$kwic_lc); 
		}

		
		$showTag="";
		if ($tag_after=~m/<(pause[^\/]*)\/>/) {
			$showTag = " [$1]";
		}  elsif ($tag_after=~m/<\/trunc>/) {
 			$showTag = "-- ";
 		}
		
		$word=~m/\A(.*)\/(.*?)\/(w|c|x)\Z/;
		$word = $1;
		$tag = $2;
		$attribute = $3;
		
		if ($space) {
			$space = " ";
		} else {
			$space = "";
		}

		if ($thePos == 0) {
			if ($params{tag}) {
				$kwic_match = $kwic_match . $showTagBefore . $word . "_$tag" . $showTag . $space;
			} else {
				$kwic_match = $kwic_match . $showTagBefore . $word . "º_$tag°" . $showTag . $space;
			}
		} else {
			$kwic_match = $kwic_match . $showTagBefore . $word . "º_$tag°" . $showTag . $space;
		}
	}
	$kwic_match=~s/ \Z//;
	$kwic_rc = $space . $kwic_rc if ($space);
	if ($kwic_match=~s/ \[pause[^\]]*\]\Z//) {
		$kwic_rc = $& . $kwic_rc;
	}
	
	$theRetrData = $kwic_match;
	
	$check = $theRetrData =~ s/º[^°]+°\Z//;
	if ($check) {
		$cutoff=$&;
		$cutoffLength = length($cutoff);
		$len -= $cutoffLength;
	}
	$theRetrData =~ s/º[^°]+°//g;
	$theRetrDataLink=$theRetrData;
	$theRetrDataLink=~s/(\W)/sprintf("%%%x", ord($1))/eg;
	

	# prepare tagged context for tooltip
	$context1 = substr($kwic_lc, -80, 80);
	$length = length($context1);
	$context1=~s/\A\S+// if ($length == 80);
	$context2 = substr($kwic_rc, 0, 80);
	$length = length($context2);
	$context2=~s/\S+\Z// if ($length == 80);
	
	$environment = $context1 . " <FONT COLOR=\"#DD0000\">" . $kwic_match . "<FONT COLOR=\"#000066\"> " . $context2 . " ";
	$environment=~s/º//g;
	$environment=~s/°//g;
	$environment=~s/ \Z//;
	$environment =~s/'/\\'/g;
	$environment =~s/"/&quot;/g;

	$pos = $sortpos - 1;
		
	if ($params{view} eq "list") {

		if ($num) {
			$theURL = getURLparams();
			
			if ($showTooltip eq "yes") {
				$link = '<A HREF="/' . $bwCGIalias . '/' . ${dispClean} . '?' . $theURL . '&text=' . $text . '&refnum=' . 
				$hitCount . '&theShowData=' . $theRetrDataLink . '&len=' . $len . 
				"&showTheTag=0&color=0&begin=$num&token_offset=$token_offset&nodeCount=$nodeCount&hitSunit=$num&spids=1&interval=11&urlTest=yes\" onmouseover=\"return escape('$environment')\">";
			} else {
				$link = '<A HREF="/' . $bwCGIalias . '/' . ${dispClean} . '?' . $theURL . '&text=' . $text . '&refnum=' . 
				$hitCount . '&theShowData=' . $theRetrDataLink . '&len=' . $len . 
				"&showTheTag=0&color=0&begin=$num&token_offset=$token_offset&nodeCount=$nodeCount&hitSunit=$num&spids=1&interval=11&urlTest=yes\">";
			}
			if (!$authLevel) {
				$insert="<A onmouseover=\"return escape('$environment')\"><B>$theRetrData<\/B></A>";
				
			} else {
				$insert="<B>$link$theRetrData<\/A><\/B>";
			}
			$str = $kwic_lc . "ª"  . $kwic_rc;
		} else {
			$insert="<B>$theRetrData<\/B>";
			$str = $kwic_lc . "ª"  . $kwic_rc;
		}
		
	} else {
		
		$str = $kwic_lc . "ª"  . $kwic_rc;
		$leftCol = $kwic_lc;
		$rightCol = $kwic_rc;

		if ($num) {
			$theURL = getURLparams();
			
			if ($showTooltip eq "yes") {
				$link = '<A HREF="/' . $bwCGIalias . '/' . ${dispClean} . '?' . $theURL . '&text=' . $text . '&refnum=' . 
				$hitCount . '&theShowData=' . $theRetrDataLink . '&len=' . $len . 
				"&showTheTag=0&color=0&begin=$num&token_offset=$token_offset&nodeCount=$nodeCount&hitSunit=$num&spids=1&interval=11&urlTest=yes\" onmouseover=\"return escape('$environment')\">";
			} else {
				$link = '<A HREF="/' . $bwCGIalias . '/' . ${dispClean} . '?' . $theURL . '&text=' . $text . '&refnum=' . 
				$hitCount . '&theShowData=' . $theRetrDataLink . '&len=' . $len . 
				"&showTheTag=0&color=0&begin=$num&token_offset=$token_offset&nodeCount=$nodeCount&hitSunit=$num&spids=1&interval=11&urlTest=yes\">";
			}
			
			if (!$authLevel) {
				$insert = "&nbsp;<\/TD><TD NOWRAP ALIGN=\"MIDDLE\"><A onmouseover=\"return escape('$environment')\"><B>$theRetrData<\/A><\/B><\/TD><TD NOWRAP>&nbsp;";
			} else {
				$insert = "&nbsp;<\/TD><TD NOWRAP ALIGN=\"MIDDLE\"><B>$link$theRetrData<\/A><\/B><\/TD><TD NOWRAP>&nbsp;";
			}
			$str= "$leftColª$rightCol";
			
		} else {
			$insert = "&nbsp;<\/TD><TD NOWRAP ALIGN=\"MIDDLE\"><B>$theRetrData<\/B><\/TD><TD NOWRAP>&nbsp;";
			$str = "$leftColª$rightCol";
		}
	}
	# toolbar info
	if ($oldText ne $text) {
		($link2, $markup) = &createFileLink($text);
		$oldText = $text;
	}
	
	$str =~ s/ª/$insert/;
	$str =~ s/<u / <u /go;
	$str =~ s/Ï/</g;
	$str =~ s/å/>/g;
	$str =~ s/º[^°]+°//g;
		

	return($str, $lineIndicator, $num, $link2);	
}


sub createFileLink {
	# puts tooltip over fileInfo link
	local($text) = $_[0];
	local($link);
	local($markup);

	$sqlQuery = "SELECT title, num_orthogr_words, numtokens, numwords, numPuns, numSentences, 
			alltim, alltyp, scgdom, sdeage, sdecla, sdesex, spolog, sporeg, wriaag, wriad, wriase, wriaty, wriaud, wridom, wrilev, wrimed, 
			wripp, wrisam, wrista, writas, allava, spowri, derivedTextType, genre  
			FROM headerInfo WHERE fname = '$text'";
	$sth3 = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
	$sth3->execute or bark("Can't execute $sqlQuery: " . $sth3::errstr);
	
	($title, $num_orthogr_words, $numtokens, $numwords, $numPuns, $numSentences, $alltim, $alltyp, 
	$scgdom, $sdeage, $sdecla, $sdesex, $spolog, $sporeg, $wriaag, $wriad, $wriase, $wriaty, 
	$wriaud, $wridom, $wrilev, $wrimed, $wripp, $wrisam, $wrista, $writas, $allava, $spowri, $derivedTextType, $genre) = $sth3->fetchrow_array;
	
	$averageSentenceLength = int((($numwords / $numSentences) * 10000) + 0.5)/ 10000;
	$showString = "<B>$text: $title</B><BR>--------------------<BR>";
	$value = "spowri=$spowri";
	$showString .= "<i>Spoken or Written:</i> <b>$catValues{$value}</b><BR>";

	$numwordsDecimal = makeDecimals($numwords);
	$showString .= "<i>Number of Words (tagged items):</i> <b>$numwordsDecimal</b><BR>";
	$showString .= "<i>Average sentence length (w-tags per s-unit):</i> <b>$averageSentenceLength</b><BR>";
	
	$value = "derivedtexttype=$derivedTextType";
	$showString .= "$typeValues{derivedtexttype}: <b>$catValues{$value}</b><BR>";
	$value = "genre=$genre";
	$showString .= "$typeValues{genre}: <b>$catValues{$value}</b><BR>";
	$value = "alltyp=$alltyp";
	$showString .= "$typeValues{alltyp}: <b>$catValues{$value}</b><BR>";
	$value = "alltim=$alltim";
	$showString .= "$typeValues{alltim}: <b>$catValues{$value}</b><BR>";
	
	if ($spowri == 2) {
		if ($alltyp == 2) {
			$value="scgdom=$scgdom";
			$showString .= "<i>$typeValues{scgdom}:</i> <b>$catValues{$value}</b><BR>";
		} else {
			$value="sdeage=$sdeage";
			$showString .= "<i>$typeValues{sdeage}:</i> <b>$catValues{$value}</b><BR>";
			$value="sdecla=$sdecla";
			$showString .= "<i>$typeValues{sdecla}:</i> <b>$catValues{$value}</b><BR>";
			$value="sdesex=$sdesex";
			$showString .= "<i>$typeValues{sdesex}:</i> <b>$catValues{$value}</b><BR>";
		}
		$value="spolog=$spolog";
		$showString .= "<i>$typeValues{spolog}:</i> <b>$catValues{$value}</b><BR>";
		$value="sporeg=$sporeg";
		$showString .= "<i>$typeValues{sporeg}:</i> <b>$catValues{$value}</b><BR>";
	} else {
		$value="wriaag=$wriaag";
		$showString .= "<i>$typeValues{wriaag}:</i> <b>$catValues{$value}</b><BR>";
		$value="wriad=$wriad";
		$showString .= "<i>$typeValues{wriad}:</i> <b>$catValues{$value}</b><BR>";
		$value="wriase=$wriase";
		$showString .= "<i>$typeValues{wriase}:</i> <b>$catValues{$value}</b><BR>";
		$value="wriaty=$wriaty";
		$showString .= "<i>$typeValues{wriaty}:</i> <b>$catValues{$value}</b><BR>";
		$value="wriaud=$wriaud";
		$showString .= "<i>$typeValues{wriaud}:</i> <b>$catValues{$value}</b><BR>";
		$value="wridom=$wridom";
		$showString .= "<i>$typeValues{wridom}:</i> <b>$catValues{$value}</b><BR>";
		$value="wrilev=$wrilev";
		$showString .= "<i>$typeValues{wrilev}:</i> <b>$catValues{$value}</b><BR>";
		$value="wrimed=$wrimed";
		$showString .= "<i>$typeValues{wrimed}:</i> <b>$catValues{$value}</b><BR>";
		$value="wripp=$wripp";
		$showString .= "<i>$typeValues{wripp}:</i> <b>$catValues{$value}</b><BR>";
		$value="wrisam=$wrisam";
		$showString .= "<i>$typeValues{wrisam}:</i> <b>$catValues{$value}</b><BR>";
		$value="wrista=$wrista";
		$showString .= "<i>$typeValues{wrista}:</i> <b>$catValues{$value}</b><BR>";
		$value="writas=$writas";
		$showString .= "<i>$typeValues{writas}:</i> <b>$catValues{$value}</b><BR>";
	}
	$showString =~s/'/\\'/g;
	$showString =~s/"/&quot;/g;
	if ($showTooltip eq "yes") {
		$link = "<A HREF=\"/$bwCGIalias/${fileInfo}?text=$text&urlTest=yes\" onmouseover=\"return escape('$showString')\">";
	} else {
		$link = "<A HREF=\"/$bwCGIalias/${fileInfo}?text=$text&urlTest=yes\">";
	}

	return($link, $markup);
}

sub wrongInput {

	print <<FOUL;
		Page $params{chunk} is not a valid page!! Please select a page within the range indicated!<BR>
		<HR> End of output.

FOUL
	&printFooter();
	&CQPdisconnect();
	exit(0);
}

sub saySorry {
	
	my $input = $_[0];
	
	$errorType="";
	if ($params{theData}=~m/\'/) {
		$check=$params{theData}=~m/\"/;
		$errorType="<B>Possible reason:</B> you are using an apostrophe without quotation marks.<BR>Please consult the manual to find out how to search for contracted forms.<BR><BR>" unless $check;
	}
	
	if ($input eq "no_files") {
		$errorText = "<BR><B>There are no files that match your restrictions.</B><BR><BR>";
	} else {
		$errorText = "<BR><B>There are no matches for your query.</B><BR><BR>";
	}
	
	print <<END;
		<TABLE BORDER="0" CELLPADDING=3 CELLSPACING=2 WIDTH="100%">
			<TR>
				<TD BGCOLOR="#FF6666">
					<BIG><B>BNCweb query result</B></BIG>
				</TD>
			</TR>
			<TR>
				<TD HEIGHT=40>
					$errorText
					$errorType
				</TD>
			</TR>
		</TABLE>
END
}


sub output3 {
	my $chunk = $_[0];
		
		#written texts
		$chunk=~s/<gap reason=anonymization desc=\"last or full name\"\/>/&lt\;name&gt\;/go;
		$chunk=~s/\<gap(.*?)\/>/&lt\;gap${1}&gt\;/go;
		#spoken texts
		$chunk=~s/\<pause(.*?)\/>/ &lt\;pause${1}&gt\; /go;
		$chunk=~s/\<\/trunc>/®--/go;
		$chunk=~s/(\s)?®--/--/go;
		$chunk=~s/\<vocal (.*?)desc=((\")?([^\>]+)(\")?)(.*?)>/ &lt\;${1}${2}${3}&gt\;/go;
		$chunk=~s/\<event (.*?)desc=((\")?([^\>]+)(\")?)(.*?)>/ &lt\;${1}${2}${3}&gt\;/go;
		# for some reason, two '"' are sometimes produced...
		$chunk=~s/\"{2,}/\"/g;
		$chunk=~s/\<unclear(.*?)\/>/&lt\;unclear$1&gt\;/go;
		$chunk=~s/\<shift new=\"?([^>\"]*)\"?\>/&lt\;voice quality: $1&gt\;/go;
		$chunk=~s/\<shift\>/&lt\;end of voice quality&gt\;/go;		
	
	return ($chunk);
}

sub checkCache {
	my $theData = $_[0];
	my $subcorpus = $_[1];
	my $qName = $_[2];
	my $thModeCheck = $_[3];
	
	my $theDataQ = $bncHandle->quote($theData);
	my $thModeCheckQ = $bncHandle->quote($thModeCheck);
	my $subcorpusQ = $bncHandle->quote($subcorpus);
	my $copied = 0;
		
	if ($thModeCheck) {
		my $sqlQuery = "SELECT originalFile, queryID FROM savedQueries where query = $theDataQ and thMode = $thModeCheckQ and subcorpus <> '###' limit 1";
		$sth8 = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
		$sth8->execute or bark("Can't execute $sqlQuery: ". $sth8::errstr);	
	} else {
		my $sqlQuery = "SELECT originalFile, queryID FROM savedQueries where initialQuery = 1 and query = $theDataQ and theRestrictions = $subcorpusQ and subcorpus <> '###' limit 1";
		$sth8 = $bncHandle->prepare($sqlQuery) or bark("Can't prepare $sqlQuery: " . $bncHandle::errstr);
		$sth8->execute or bark("Can't execute $sqlQuery: ". $sth8::errstr);
	}
	@rowArray=$sth8->fetchrow_array;
	my $originalFile = $rowArray[0];
	
	
	my $queryID = $rowArray[1];
	
	if ($originalFile) {
		#warn "/$bwTempPath/$bwCorpus:$originalFile";
		if (-f "/$bwTempPath/$bwCorpus:$originalFile") {
		setParam("theID", "$queryID");
		setParam("queryID", "$queryID");
		return("$originalFile");
		} else {
			$sqlQuery = "DELETE FROM savedQueries where originalFile = '$originalFile'";
			$bncHandle->do($sqlQuery) or bark("Can't delete: $sqlQuery: " . $bncHandle::errstr);
			return("0", "");
		}
	} else {
		return("0", "");
	}
}

sub updateSavedQueries {
	$theTime = int(time);

	$thModeInsert = $params{thMode};		
	$thModeInsert = $bncHandle->quote($thModeInsert);
	$insertTheData = $params{theData};
	$insertTheData = $bncHandle->quote($insertTheData);
	$insertSimpleQuery = $params{simpleQuery};
  ## ***DEL***  # $insertSimpleQuery = "###" . $insertSimpleQuery if ($params{theData}=~m/\A###/);
	$insertSimpleQuery = $bncHandle->quote($insertSimpleQuery);
	$theOriginalURL = $bncHandle->quote($qString);
	$theMeta = $theRestrictions;
	unless ($theMeta) {
		if ($params{qtype} == 1) {
			$theMeta = "(spowri=1)";	
		} elsif ($params{qtype} == 2) {
			$theMeta = "(spowri=2)";	
		}
	}
	$theRestrictionsQuote = $bncHandle->quote($theMeta);
	$theRestrictionsQuote = '\'\'' unless ($theMeta);
			
	# put query in saved queries database with saved status 0		
	$subcorp = $params{subcorpus};
	$subcorp = $metatextual if ($subcorp=~m/\Alast_(written|spoken)\Z/);
	$subcorp = "" if ($subcorp eq "no_subcorpus");
	if ($subcorp) {
		$subcorp = "###" unless ($subcorp=~m/=/);
	}
	$subcorpQuote = $bncHandle->quote($subcorp);
	$subcorpQuote  = '\'\'' unless ($subcorp);

	$timeTaken = 0 if (!$timeTaken);
	if ($params{recreate}) {

		# obsolete code?
# 		$sqlQuery = "insert into savedQueries (user, queryID, query, hits, time_of_query, saved, link, thMode, initialQuery, simpleQuery, originalFile, theID, subcorpus, fileSize) 
# 				values 
# 				('$username', '$params{queryID}', $insertTheData, $numOfSolutions, $theTime, 0, $theOriginalURL, $thModeInsert, 0, $insertSimpleQuery, '$params{queryID}', '$params{queryID}', '###', $fileSize)";
# 		warn $sqlQuery;
# 		#setParam("theID", "$userCheck");
# 		$bncHandle->do($sqlQuery) or bark("Can't insert $sqlQuery: " . $bncHandle::errstr);
# 		setParam("recreate", "");
		
	} else {
		$firstQuery = "0" if (!$firstQuery);
		if ($performThinning) {
			# some data still missing!
			$sqlQuery = "insert into savedQueries (user, queryID, query, hits, time_of_query, saved, link, thMode, initialQuery, simpleQuery, originalFile, theID, subcorpus, fileSize) 
					values 
				('$username', '$userCheck', $insertTheData, $numOfSolutions, $theTime, 0, $theOriginalURL, $thModeInsert, 0, $insertSimpleQuery, '$userCheck', '$params{theID}', '###', $fileSize)";
#			} elsif (($performRandomize) || ($performUnRandomize)) {
#				$sqlQuery = "insert into savedQueries (user, queryID, query, hits, time_of_query, saved, link, thMode, initialQuery, simpleQuery, originalFile, theID, subcorpus, fileSize) 
#						values 
#					('$username', '$userCheck', $insertTheData, $numOfSolutions, $theTime, 0, $theOriginalURL, $thModeInsert, $firstQuery, $insertSimpleQuery, '$userCheck', '$params{theID}', $subcorpQuote, $fileSize)";
		} else {
			$sqlQuery = "insert into savedQueries (user, queryID, query, hits, time_of_query, saved, link, initialQuery, simpleQuery, originalFile, theID, theRestrictions, subcorpus, fileSize, execute_time, thMode) 
					values 
				('$username', '$userCheck', $insertTheData, $numOfSolutions, $theTime, 0, $theOriginalURL, $firstQuery, $insertSimpleQuery, '$userCheck', '$userCheck', $theRestrictionsQuote, $subcorpQuote, $fileSize, $timeTaken, $thModeInsert)";
			setParam("theID", "$userCheck");
		}
		$bncHandle->do($sqlQuery) or bark("Can't insert $sqlQuery: " . $bncHandle::errstr);
		setParam("queryID", "$userCheck");
	}
		
	#setParam{"recreate", ""};

}
