text:
<?php

##################################################################################
#    HOTELDRUID
#    Copyright (C) 2001-2016 by Marco Maria Francesco De Santis (marco@digitaldruid.net)
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    any later version accepted by Marco Maria Francesco De Santis, which
#    shall act as a proxy as defined in Section 14 of version 3 of the
#    license.
#
#    This program 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
##################################################################################

error_reporting(E_ALL ^ E_NOTICE);
if (function_exists('mb_internal_encoding')) mb_internal_encoding('UTF-8');
if (function_exists('date_default_timezone_set')) if (!ini_get('date.timezone')) date_default_timezone_set('UTC');

# nel caso fosse settato register_globals = Off
if (@is_array($_POST)) reset($_POST);
for($num1 = 0 ; $num1 < count($_POST); $num1++) {
$var_POST = key($_POST);
if (!isset($$var_POST)) $$var_POST = $_POST[$var_POST];
next($_POST);
} # fine for $num1
if (@is_array($_GET)) reset($_GET);
for($num1 = 0 ; $num1 < count($_GET); $num1++) {
$var_GET = key($_GET);
if (!isset($$var_GET)) $$var_GET = $_GET[$var_GET];
next($_GET);
} # fine for $num1

if (@is_file(C_DATI_PATH."/tema.php")) include(C_DATI_PATH."/tema.php");
else {
unset($tema);
$trad_ui = 0;
} # fine else if (@is_file(C_DATI_PATH."/tema.php"))

#$pag = explode("/", $SCRIPT_NAME);
#$pag = end($pag);
$tablepersonalizza = $PHPR_TAB_PRE."personalizza";

#@include("./includes/costanti.php");
#@include(C_DATI_PATH."/costanti.php");
define('C_PHPR_VERSIONE_NUM',2.14);
define('C_PHPR_VERSIONE_TXT',"2.1.4");

# Se non si specifica nessun anno uso l'attuale
$anno_corrente = date("Y",(time() + (C_DIFF_ORE * 3600)));
if (!$anno) {
if ($id_sessione) $anno = substr($id_sessione,0,4);
else {
if (!defined('C_GIORNI_NUOVO_ANNO')) include("./costanti.php");
$anno = date("Y",(time() + (C_DIFF_ORE * 3600) - (C_GIORNI_NUOVO_ANNO * 86400)));
# Se ci troviamo nel periodo di C_GIORNI_NUOVO_ANNO ma il nuovo anno è già stato creato
if ($anno_corrente != $anno) {
if (@is_file(C_DATI_PATH."/selectperiodi$anno_corrente.1.php")) $anno = $anno_corrente;
} # fine if ($anno_corrente != $anno)
} # fine else if ($id_sessione)
} # fine if (!$anno)

if ($vers_hinc) $vers_hinc = "?v=".C_PHPR_VERSIONE_NUM;

if ($_SERVER['SERVER_NAME']) $HOSTNAME = $_SERVER['SERVER_NAME'];
elseif ($SERVER_NAME) $HOSTNAME = $SERVER_NAME;
$HOSTNAME = htmlspecialchars($HOSTNAME);

if (strstr($_SERVER['HTTP_USER_AGENT'],'(iP') or strstr($_SERVER['HTTP_USER_AGENT'],'Android') or strstr($_SERVER['HTTP_USER_AGENT'],'webOS') or strstr($_SERVER['HTTP_USER_AGENT'],'BlackBerry') or strstr($_SERVER['HTTP_USER_AGENT'],'Mobile') or strstr($_SERVER['HTTP_USER_AGENT'],'Opera Mobi')) $mobile_device = 1;
else $mobile_device = 0;

if (function_exists('aggslashdb')) {
$anno = aggslashdb($anno);
$id_sessione = aggslashdb($id_sessione);
$HOSTNAME = aggslashdb($HOSTNAME);
} # fine if (function_exists('aggslashdb'))
else {
$anno = addslashes($anno);
$id_sessione = addslashes($id_sessione);
$HOSTNAME = addslashes($HOSTNAME);
} # fine else if (function_exists('aggslashdb'))

if (!$parole_sost) {
function mex ($messaggio,$pagina) {

global $lingua_mex;
if ($lingua_mex != "ita") {
include("./includes/lang/$lingua_mex/$pagina");
} # fine if ($lingua_mex != "ita")
elseif ($pagina == "unit.php") include("./includes/unit.php");

return $messaggio;

} # fine function mex
} # fine if (!$parole_sost)

else {
function mex ($messaggio,$pagina) {

global $lingua_mex;
if ($lingua_mex != "ita") {
include("./includes/lang/$lingua_mex/$pagina");
} # fine if ($lingua_mex != "ita")
elseif ($pagina == "unit.php") include("./includes/unit.php");
if (substr($messaggio,0,4) != 'var_') @include(C_DATI_PATH."/parole_sost.php");

return $messaggio;

} # fine function mex
} # fine else if (!$parole_sost)

function controlla_anno ($anno) {

$verificato = "SI";
$verifica_num = preg_replace("/[0-9]/","",$anno);
if (strcmp($verifica_num,"")) $verificato = "NO";
if (strlen($anno) != 4) $verificato = "NO";
$prime_cifre =substr ($anno,0,2);
if ($prime_cifre != 18 and $prime_cifre != 19 and $prime_cifre != 20 and $prime_cifre != 21) $verificato = "NO";

return $verificato;

} # fine function controlla_anno

# controllo che l'anno passato a tutte le pagine non sia falso
if (controlla_anno($anno) != "SI") $anno = "";

# parametro deve essere positivo o 0
function controlla_num_pos ($num) {

$verificato = "SI";
if (!strcmp($num,"")) $verificato = "NO";
$verifica_num = preg_replace("/[0-9]/","",$num);
if (strcmp($verifica_num,"")) $verificato = "NO";

return $verificato;

} # fine function controlla_num_pos

function controlla_num ($num) {

$verificato = "SI";
$uno = substr($num,0,1);
if ($uno == "-") $num = substr($num,1);
$verifica_num = preg_replace("/[0-9]/","",$num);
if (strcmp($verifica_num,"")) $verificato = "NO";

return $verificato;

} # fine function controlla_num

function nome_valuta ($id_utente_valuta = "") {

global $tablepersonalizza;
if ($id_utente_valuta) $id_utente = $id_utente_valuta;
else global $id_utente;
$nome_valuta = esegui_query("select * from $tablepersonalizza where idpersonalizza = 'valuta' and idutente = '$id_utente'");
$nome_valuta = risul_query($nome_valuta,0,'valpersonalizza');

return $nome_valuta;

} # fine function nome_valuta

function stile_data ($id_utente_st = "") {

global $tablepersonalizza;
if ($id_utente_st) $id_utente = $id_utente_st;
else global $id_utente;
$stile_data = esegui_query("select * from $tablepersonalizza where idpersonalizza = 'stile_data' and idutente = '$id_utente'");
$stile_data = risul_query($stile_data,0,'valpersonalizza');

return $stile_data;

} # fine function stile_data

function formatta_data ($data,$stile_data="europa") {

$giorno = substr($data,8,2);
$mese = substr($data,5,2);
$anno = substr($data,0,4);
#$formato = "d-m-Y";
#if ($stile_data == 'usa') $formato = "m-d-Y";
#$data_formattata = date ($formato, mktime(0,0,0,$mese,$giorno,$anno));
switch ($stile_data) {
case "usa": $data_formattata = $mese."-".$giorno."-".$anno; break;
default: $data_formattata = $giorno."-".$mese."-".$anno;
} # fine switch ($stile_data)
$data_formattata .= substr($data,10);

return $data_formattata;

} # fine function formatta_data

function stile_soldi ($id_utente_st = "") {

global $tablepersonalizza;
if ($id_utente_st) $id_utente = $id_utente_st;
else global $id_utente;
$stile_soldi = esegui_query("select * from $tablepersonalizza where idpersonalizza = 'stile_soldi' and idutente = '$id_utente'");
$stile_soldi = risul_query($stile_soldi,0,'valpersonalizza');

return $stile_soldi;

} # fine function stile_soldi

function punti_in_num ($num,$stile_soldi="europa",$decimali="") {

#$uno = substr ($num,0,1);
#if ($uno == "-") { $num = substr ($num,1); }
#$num = strrev($num);
#$num = chunk_split($num,3,".");
#$num = substr ($num,0,-1);
#$num = strrev($num);
#if ($uno == "-") { $num = "-".$num; }

if (!strcmp($decimali,"")) {
if (!strstr($num,".") or substr(strstr($num,"."),1) == 0) $decimali = 0;
else $decimali = 2;
} # fine (!strcmp($decimali,""))
if ($stile_soldi == "usa") $num = number_format((double) $num,$decimali);
else $num = number_format((double) $num,$decimali,",",".");

return $num;

} # fine function punti_in_num

function virgola_in_num ($num,$stile_soldi="europa") {

if ($stile_soldi == "europa") $num = str_replace(".",",",$num);

return $num;

} # fine function virgola_in_num

function controlla_soldi ($num,$pos="NO") {

$verificato = "SI";
$uno = substr ($num,0,1);
if ($uno == "-" and $pos == "NO") $num = substr($num,1);
#$num = str_replace(",",".",$num);
$parti = explode(".",$num);
if (count($parti) > 2) $verificato = "NO";
$num = str_replace(".","",$num);
$verifica_num = preg_replace("/[0-9]/","",$num);
if (strcmp($verifica_num,"")) $verificato = "NO";

return $verificato;

} # fine function controlla_soldi

function formatta_soldi ($num) {

$num = str_replace(",",".",$num);
$parti = explode(".",$num);
if (count($parti) == 2) {
if ($parti[1]) {
if (strlen($parti[1]) > 2) {
$parti[1] = substr($parti[1],0,2).".".substr($parti[1],2);
$parti[1] = round($parti[1]);
} # fine if (strlen($parti[1]) > 2)
$num = $parti[0].".".$parti[1];
settype ($num,double);
} # fine if ($parti[1])
else $num = $parti[0];
} # fine if (count($parti) == 2)

return $num;

} # fine function formatta_soldi

function togli_acapo($stringa) {

$stringa = str_replace("\r\n","",$stringa);
$stringa = str_replace("\r","",$stringa);
$stringa = str_replace("\n","",$stringa);
$stringa = str_replace("
","",$stringa);

return $stringa;

} # fine function togli_acapo

function aggiungi_slash($stringa) {

$stringa = str_replace("\\","\\\\",$stringa);
$stringa = str_replace("\$","\\\$",$stringa);
$stringa = str_replace("\"","\\\"",$stringa);

return $stringa;

} # fine function aggiungi_slash

function strip_magic_slashs ($val) {
if (@get_magic_quotes_gpc()) $val = stripslashes($val);
return $val;
} # fine function strip_magic_slashs

function prendi_numero_versione ($tableversioni,$idversioni="idversioni",$num_versione="num_versione") {

$versione = esegui_query("select * from $tableversioni where $idversioni = '2'");
if (numlin_query($versione)) {
$versione = risul_query($versione,0,$num_versione);
$versione = $versione + 1;
if ($versione >= 99999990) $versione = 100;
esegui_query("update $tableversioni set $num_versione = '$versione' where $idversioni = '2'");
} # fine if (numlin_query($versione))
else {
$versione = 100;
esegui_query("insert into $tableversioni ($idversioni,$num_versione) values ('2','100') ");
} # fine else if (numlin_query($versione))

return $versione;

} # fine function prendi_numero_versione

#Funzione per controllare le sessioni

$id_utente = "";

function controlla_login (&$numconnessione,&$PHPR_TAB_PRE,&$id_sessione,$nome_utente_phpr,$password_phpr,$anno) {

if (defined("C_FILE_SCADENZA_ACCOUNT") and C_FILE_SCADENZA_ACCOUNT != "") {
$scadenza = trim(@implode("",@file("./".C_FILE_SCADENZA_ACCOUNT)));
$adesso = date("YmdHis");
if (!$scadenza or $scadenza < $adesso) {
$disattivato = "SI";
if (defined("C_HTML_PRE_LOGIN") and C_HTML_PRE_LOGIN != "") echo C_HTML_PRE_LOGIN;
echo "Expired account.
";
if (defined("C_HTML_POST_LOGIN") and C_HTML_POST_LOGIN != "") echo C_HTML_POST_LOGIN;
} # fine (!$scadenza or $scadenza < $adesso)
} # fine (defined("C_FILE_SCADENZA_ACCOUNT") and C_FILE_SCADENZA_ACCOUNT != "")
if (!$disattivato) {

global $lingua_mex,$tema,$pag,$ILIKE,$LIKE,$DATETIME,$nome_utente_login,$PHPR_LOG;
@include(C_DATI_PATH."/lingua.php");
@include(C_DATI_PATH."/versione.php");
if ($lingua[1] and @is_dir("./includes/lang/".$lingua[1])) $lingua_mex = $lingua[1];
else $lingua_mex = "ita";
$nome_utente_login = "";

if (!is_file(C_DATI_PATH."/abilita_login")) $id_utente = 1;

else {

if (!$id_sessione) {
if ($nome_utente_phpr and $password_phpr) {
if (!$numconnessione) {
include(C_DATI_PATH."/dati_connessione.php");
include("./includes/funzioni_$PHPR_DB_TYPE.php");
$numconnessione = connetti_db($PHPR_DB_NAME,$PHPR_DB_HOST,$PHPR_DB_PORT,$PHPR_DB_USER,$PHPR_DB_PASS,$PHPR_LOAD_EXT);
} # fine if (!$numconnessione)
$nome_utente_phpr = aggslashdb($nome_utente_phpr);
$password_phpr = aggslashdb($password_phpr);
$tableutenti = $PHPR_TAB_PRE."utenti";
$tablesessioni = $PHPR_TAB_PRE."sessioni";
$tableversioni = $PHPR_TAB_PRE."versioni";
$tabletransazioni = $PHPR_TAB_PRE."transazioni";
$tablepersonalizza = $PHPR_TAB_PRE."personalizza";
$tabelle_lock = array($tableversioni,$tablesessioni,$tabletransazioni);
$altre_tab_lock = array($tablepersonalizza,$tableutenti);
$tabelle_lock = lock_tabelle($tabelle_lock,$altre_tab_lock);

$sec_log_sbagliati = 5;
$limite_login_sbagliati = date("Y-m-d H:i:s",(time() - $sec_log_sbagliati + (C_DIFF_ORE * 3600)));
$ultimo_login_sbagliato = esegui_query("select ultimo_accesso from $tabletransazioni where tipo_transazione = 'err_l' and ultimo_accesso >= '$limite_login_sbagliati'");
if (numlin_query($ultimo_login_sbagliato) > 0) {
$mostra_form_login = "SI";
$messaggio_errore .= mex("Dopo un login
errato
 si devono attendere","funzioni.php")." $sec_log_sbagliati ".mex("secondi","funzioni.php").".

";
} # fine if (numlin_query($ultimo_login_sbagliato) > 0)
else {
$num_log_sbagliati = 7;
$num_log_avviso = 3;
$minuti_durata_sessione = esegui_query("select valpersonalizza_num from $tablepersonalizza where idpersonalizza = 'minuti_durata_sessione' and idutente = '1'");
$minuti_durata_sessione = risul_query($minuti_durata_sessione,0,'valpersonalizza_num');
$limite_transazioni_vecchie = date("Y-m-d H:i:s",(time() - ($minuti_durata_sessione * 60) + (C_DIFF_ORE * 3600)));
esegui_query("delete from $tabletransazioni where ultimo_accesso <= '$limite_transazioni_vecchie'");
$login_sbagliati = esegui_query("select tipo_transazione from $tabletransazioni where tipo_transazione = 'err_l' and dati_transazione1 = '$nome_utente_phpr'");
$login_sbagliati = numlin_query($login_sbagliati);
if ($login_sbagliati >= $num_log_sbagliati) {
$messaggio_errore .= mex("Numero eccesivo di login
errati
 negli ultimi","funzioni.php")." $minuti_durata_sessione ".mex("minuti","funzioni.php").".

";
if (defined("C_HTML_POST_LOGIN") and C_HTML_POST_LOGIN != "") $messaggio_errore .= mex("È possibile reimpostare la password dal proprio account di hosting","funzioni.php").".".C_HTML_POST_LOGIN;
} # fine if ($login_sbagliati >= $num_log_sbagliati)
else {

$utente = esegui_query("select * from $tableutenti where nome_utente = '$nome_utente_phpr'");
if (numlin_query($utente) == 1) {
$nome_utente_login = risul_query($utente,0,'nome_utente');
$tipo_pass = risul_query($utente,0,'tipo_pass');
$password = risul_query($utente,0,'password');
if ($tipo_pass == "5") {
if (C_VERSIONE_ATTUALE > 1.32) {
$salt = risul_query($utente,0,'salt');
for ($num1 = 0 ; $num1 < 15 ; $num1++) $password_phpr = md5($password_phpr.substr($salt,0,(20 - $num1)));
} # fine if (C_VERSIONE_ATTUALE > 1.32)
else $password_phpr = md5($password_phpr);
} # fine if ($tipo_pass == "5")

# login effettuato con successo
if ($password == $password_phpr and $tipo_pass != "n") {
$id_utente = risul_query($utente,0,'idutenti');
$adesso = $anno.date("mdHis",(time() + (C_DIFF_ORE * 3600)));
$versione_unica = prendi_numero_versione($tableversioni);
list($usec, $sec) = explode(' ', microtime());
mt_srand((float) $sec + ((float) $usec * 100000));
$val_casuale = mt_rand(100000,999999);
$id_sessione = $adesso.$val_casuale.$versione_unica;
$ultimo_accesso = date("Y-m-d H:i:s",(time() + (C_DIFF_ORE * 3600)));
global $_SERVER,$REMOTE_ADDR,$REMOTE_PORT,$HTTP_USER_AGENT;
if ($_SERVER['REMOTE_ADDR']) $REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
$REMOTE_ADDR = aggslashdb($REMOTE_ADDR);
if ($_SERVER['REMOTE_PORT']) $REMOTE_PORT = $_SERVER['REMOTE_PORT'];
$REMOTE_PORT = aggslashdb($REMOTE_PORT);
if ($_SERVER['HTTP_USER_AGENT']) $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'];
$HTTP_USER_AGENT = aggslashdb($HTTP_USER_AGENT);
if ($_SERVER['HTTPS'] == "on" or $_SERVER['SERVER_PORT'] == "443") $tipo_conn = "HTTPS";
else $tipo_conn = "HTTP";
if (C_VERSIONE_ATTUALE >= 2.1) esegui_query("insert into $tablesessioni (idsessioni,idutente,indirizzo_ip,tipo_conn,user_agent,ultimo_accesso) values ('$id_sessione','$id_utente','$REMOTE_ADDR','$tipo_conn','$HTTP_USER_AGENT','$ultimo_accesso')","",$id_utente);
else esegui_query("insert into $tablesessioni (idsessioni,idutente,indirizzo_ip,user_agent,ultimo_accesso) values ('$id_sessione','$id_utente','$REMOTE_ADDR','$HTTP_USER_AGENT','$ultimo_accesso')","",$id_utente);
} # fine if ($password == $password_phpr and $tipo_pass != "n")

else $login_fallito = "SI";
} # fine if (numlin_query($utente) == 1)
else $login_fallito = "SI";
if ($login_fallito == "SI") {
$mostra_form_login = "SI";
$messaggio_errore .= mex("Nome utente o password
errati
","funzioni.php").".
";
if ($login_sbagliati >= ($num_log_sbagliati - $num_log_avviso - 1)) {
if (($num_log_sbagliati - $login_sbagliati - 1) > 1) $messaggio_errore .= mex("Mancano solo","funzioni.php")." ".($num_log_sbagliati - $login_sbagliati - 1)." ".mex("tentativi prima del blocco dei login","funzioni.php").".
";
if (($num_log_sbagliati - $login_sbagliati - 1) == 1) $messaggio_errore .= mex("Manca solo","funzioni.php")." 1 ".mex("tentativo prima del blocco dei login","funzioni.php").".
";
} # fine if (numlin_query($utente) == 1)
$messaggio_errore .= "
";
$versione_transazione = prendi_numero_versione($tableversioni);
$adesso = date("YmdHis",(time() + (C_DIFF_ORE * 3600)));
list($usec, $sec) = explode(' ', microtime());
mt_srand((float) $sec + ((float) $usec * 100000));
$val_casuale = mt_rand(100000,999999);
$ultimo_accesso = date("Y-m-d H:i:s",(time() + (C_DIFF_ORE * 3600)));
global $_SERVER,$REMOTE_ADDR;
if ($_SERVER['REMOTE_ADDR']) $REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
$REMOTE_ADDR = aggslashdb($REMOTE_ADDR);
$id_transazione = $adesso.$val_casuale.$versione_transazione;
esegui_query("insert into $tabletransazioni (idtransazioni,tipo_transazione,dati_transazione1,dati_transazione2,ultimo_accesso) values ('$id_transazione','err_l','$nome_utente_phpr','$REMOTE_ADDR','$ultimo_accesso')");
} # fine if ($login_fallito == "SI")

} # fine else if ($login_sbagliati >= $num_log_sbagliati)
} # fine else if (numlin_query($ultimo_login_sbagliato) > 0)
unlock_tabelle($tabelle_lock);
} # fine if ($nome_utente and $password)
else $mostra_form_login = "SI";
} # fine if (!$id_sessione)

else {
if (!$numconnessione) {
include(C_DATI_PATH."/dati_connessione.php");
include("./includes/funzioni_$PHPR_DB_TYPE.php");
$numconnessione = connetti_db($PHPR_DB_NAME,$PHPR_DB_HOST,$PHPR_DB_PORT,$PHPR_DB_USER,$PHPR_DB_PASS,$PHPR_LOAD_EXT);
} # fine if ($numconnessione)
$tableutenti = $PHPR_TAB_PRE."utenti";
$tablesessioni = $PHPR_TAB_PRE."sessioni";
$tablepersonalizza = $PHPR_TAB_PRE."personalizza";
$tabelle_lock = array($tableutenti,$tablesessioni);
$altre_tab_lock = array($tablepersonalizza);
$tabelle_lock = lock_tabelle($tabelle_lock,$altre_tab_lock);
$minuti_durata_sessione = esegui_query("select valpersonalizza_num from $tablepersonalizza where idpersonalizza = 'minuti_durata_sessione' and idutente = '1'");
$minuti_durata_sessione = risul_query($minuti_durata_sessione,0,'valpersonalizza_num');
$limite_sessioni_vecchie = date("Y-m-d H:i:s",(time() - ($minuti_durata_sessione * 60) + (C_DIFF_ORE * 3600)));
esegui_query("delete from $tablesessioni where ultimo_accesso <= '$limite_sessioni_vecchie'");
$ultimo_accesso = date("Y-m-d H:i:s",(time() + (C_DIFF_ORE * 3600)));
global $_SERVER,$REMOTE_ADDR,$REMOTE_PORT,$HTTP_USER_AGENT;
if ($_SERVER['REMOTE_ADDR']) $REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
$REMOTE_ADDR = aggslashdb($REMOTE_ADDR);
if ($_SERVER['REMOTE_PORT']) $REMOTE_PORT = $_SERVER['REMOTE_PORT'];
$REMOTE_PORT = aggslashdb($REMOTE_PORT);
if ($_SERVER['HTTP_USER_AGENT']) $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'];
$HTTP_USER_AGENT = aggslashdb($HTTP_USER_AGENT);
$sessione = esegui_query("select * from $tablesessioni where idsessioni = '$id_sessione'");
if (numlin_query($sessione) == 1) {
$indirizzo_ip = risul_query($sessione,0,'indirizzo_ip');
$tipo_conn = @risul_query($sessione,0,'tipo_conn');
$user_agent = risul_query($sessione,0,'user_agent');
if (($indirizzo_ip == $REMOTE_ADDR and $user_agent == $HTTP_USER_AGENT) or ($tipo_conn == "HTTPS" and ($_SERVER['HTTPS'] == "on" or $_SERVER['SERVER_PORT'] == "443"))) {
$id_utente_presunto = risul_query($sessione,0,'idutente');
$utente_presente = esegui_query("select nome_utente from $tableutenti where idutenti = '$id_utente_presunto'");
if (numlin_query($utente_presente) == 1) {
$nome_utente_login = risul_query($utente_presente,0,'nome_utente');
$id_utente = $id_utente_presunto;
esegui_query("update $tablesessioni set ultimo_accesso = '$ultimo_accesso' where idsessioni = '$id_sessione'");
} # fine if (numlin_query($utente_presente) == 1)
else $sessione_scaduta = "SI";
} # fine if (($indirizzo_ip == $REMOTE_ADDR and $user_agent == $HTTP_USER_AGENT) or...
else $sessione_scaduta = "SI";
} # fine if (numlin_query($sessione) == 1)
else $sessione_scaduta = "SI";
unlock_tabelle($tabelle_lock);
if ($sessione_scaduta == "SI") {
$mostra_form_login = "SI";
$messaggio_errore .= "".mex("Sessione
scaduta
","funzioni.php").".

";
} # fine if ($sessione_scaduta == "SI")
} # fine else if (!$id_sessione)

if ($messaggio_errore or $mostra_form_login == "SI") {
if ($pag == "aggiorna.php") $action = "aggiorna.php";
else {
if ((@is_array($_POST) or @is_array($_GET)) and $pag) {
$action = $pag;
if (@is_array($_POST)) {
reset($_POST);
for ($num1 = 0 ; $num1 < count($_POST); $num1++) {
$key = key($_POST);
if ($key != "id_sessione" and $key != "nome_utente_phpr" and $key != "password_phpr" and $key != "pass_cc" and $key != "logout") $input_var_passate .= "<input type=\"hidden\" name=\"$key\" value=\"".htmlspecialchars(strip_magic_slashs(current($_POST)))."\">";
next($_POST);
} # fine for $num1
} # fine if (@is_array($_POST))
if (@is_array($_GET)) {
reset($_GET);
for ($num1 = 0 ; $num1 < count($_GET); $num1++) {
$key = key($_GET);
if ($key != "id_sessione" and $key != "nome_utente_phpr" and $key != "password_phpr" and $key != "pass_cc" and $key != "logout") $input_var_passate .= "<input type=\"hidden\" name=\"$key\" value=\"".htmlspecialchars(strip_magic_slashs(current($_GET)))."\">";
next($_GET);
} # fine for $num1
} # fine if (@is_array($_GET))
} # fine if ((@is_array($_POST) or @is_array($_GET)) and $pag)
else $action = "inizio.php";
} # fine else if ($pag == "aggiorna.php")
$pag = "login";
if (C_NASCONDI_MARCA == "SI") $titolo = "Login";
else $titolo = mex("Login per HotelDruid","funzioni.php");
$show_bar = "NO";
$tema_corr = $tema[1];
if ($tema[1] and $tema[1] != "base" and @is_dir("./themes/".$tema[1]."/php")) include("./themes/".$tema[1]."/php/head.php");
else include("./includes/head.php");
if (!defined('C_URL_LOGO') or C_URL_LOGO == "") echo "
";
else echo "
";
echo $messaggio_errore;
} # fine if ($messaggio_errore or $mostra_form_login == "SI")
if ($mostra_form_login == "SI") {
if (@is_file(C_DATI_PATH."/dati_subordinazione.php")) include(C_DATI_PATH."/dati_subordinazione.php");
if (defined("C_HTML_PRE_LOGIN") and C_HTML_PRE_LOGIN != "") echo C_HTML_PRE_LOGIN;
$mess = $titolo;
if ($commento_subordinazione) $mess .= " ($commento_subordinazione)";
echo "<big><big>$mess:</big></big>

<form accept-charset=\"utf-8\" method=\"post\" action=\"$action\">

<input type=\"hidden\" name=\"vers_hinc\" value=\"1\">
$input_var_passate
".mex("Nome utente","funzioni.php").": <input type=\"text\" name=\"nome_utente_phpr\" size=\"12\">

".mex("Password","funzioni.php").": <input type=\"password\" name=\"password_phpr\" size=\"12\" autocorrect=\"off\" autocapitalize=\"off\">

<button class=\"login\" type=\"submit\">
".mex("Entra","funzioni.php")."
</button>

</form>";
if (defined("C_HTML_POST_LOGIN") and C_HTML_POST_LOGIN != "") echo C_HTML_POST_LOGIN;
} # fine if ($mostra_form_login == "SI")
if ($messaggio_errore or $mostra_form_login == "SI") {

# You are not authorized to remove the following copyright notice. Ask for permission info@digitaldruid.net
if (C_MOSTRA_COPYRIGHT != "NO") {
echo "

 Website engine code is copyright © by DigitalDruid.Net.
HotelDruid is a free software released under the GNU/AGPL.
";
} # fine if (C_MOSTRA_COPYRIGHT != "NO")
echo "
";

if ($tema[1] and $tema[1] != "base" and @is_dir("./themes/".$tema[1]."/php")) include("./themes/".$tema[1]."/php/foot.php");
else include("./includes/foot.php");
} # fine if ($messaggio_errore or $mostra_form_login == "SI")

if ($id_utente and ($lingua[$id_utente] == "ita" or @is_dir("./includes/lang/".$lingua[$id_utente]))) $lingua_mex = $lingua[$id_utente];
} # fine else if (!is_file(C_DATI_PATH."/abilita_login"))

if ($id_utente and $tema[$id_utente] != "base" and (!$tema[$id_utente] or !@is_dir("./themes/".$tema[$id_utente]."/php"))) $tema[$id_utente] = "base";

if (C_VERSIONE_ATTUALE < C_PHPR_VERSIONE_NUM and $id_utente and $pag != "aggiorna.php") {
if (@is_file(C_DATI_PATH."/dati_connessione.php") or @is_file("./dati/connessione_db.php") or @is_file("./datipermanenti/connessione_db.inc")) {
if ($pag == "interconnessioni.php" and $id_utente != 1) {
$id_utente_az = esegui_query("select idlocale from $PHPR_TAB_PRE"."interconnessioni where tipoid = 'id_utente_az' ");
if (numlin_query($id_utente_az) == 1) $id_utente_azione_ic = risul_query($id_utente_az,0,'idlocale');
} # fine if ($pag == "interconnessioni.php" and $id_utente != 1)
if ($id_utente == $id_utente_azione_ic) {
include("./includes/funzioni_aggiorna.php");
aggiorna_versione_phpr($numconnessione,$id_utente,$id_sessione,$nome_utente_phpr,$password_phpr,$anno);
} # fine if ($id_utente == $id_utente_azione_ic)
else {
$show_bar = "NO";
if ($tema[$id_utente] and $tema[$id_utente] != "base" and @is_dir("./themes/".$tema[$id_utente]."/php")) include("./themes/".$tema[$id_utente]."/php/head.php");
else include("./includes/head.php");
echo mex("Il database deve essere aggiornato","funzioni.php").".
";
echo "<form method=\"post\" action=\"aggiorna.php\">

<input type=\"hidden\" name=\"anno\" value=\"$anno\">
<input type=\"hidden\" name=\"id_sessione\" value=\"$id_sessione\">
<input class=\"sbutton\" type=\"submit\" value=\"".mex("Aggiorna","funzioni.php")."\">

</form>";
if ($tema[$id_utente] and $tema[$id_utente] != "base" and @is_dir("./themes/".$tema[$id_utente]."/php")) include("./themes/".$tema[$id_utente]."/php/foot.php");
else include("./includes/foot.php");
} # fine else if ($id_utente == $id_utente_azione_ic)
unset($id_utente);
} # fine if (@is_file(C_DATI_PATH."/dati_connessione.php") or...
} # fine if (C_VERSIONE_ATTUALE < C_PHPR_VERSIONE_NUM and...

return $id_utente;

} # fine if (!$disattivato)

} # fine function controlla_login

function scrivi_file ($linee,$nome_file) {

$scrittura_corretta = "SI";
if ($fileaperto = fopen("$nome_file.tmp","w+")) {
flock($fileaperto,2);
if (!@is_array($linee)) {
$linee2 = $linee;
unset($linee);
$linee[0] = $linee2;
unset($linee2);
} # fine if (!@is_array($linee))
for ($num1 = 0 ; $num1 < count($linee) ; $num1++) fwrite($fileaperto,$linee[$num1]);
flock($fileaperto,3);
fclose($fileaperto);
$linee2 = @file("$nome_file.tmp");
$num_linee2 = 0;
$ultima_linea = "";
for ($num1 = 0 ; $num1 < count($linee) ; $num1++) {
$linee[$num1] = str_replace("\r\n","\n",$linee[$num1]);
$linee[$num1] = str_replace("
","\n",$linee[$num1]);
$sub_linee = explode("\n",$linee[$num1]);
for ($num2 = 0 ; $num2 < count($sub_linee) ; $num2++) {
if ($num2 == 0)  $sub_linee[$num2] = $ultima_linea.$sub_linee[$num2];
if ($num2 != (count($sub_linee)-1)) {
if (togli_acapo($linee2[$num_linee2]) != $sub_linee[$num2]) $scrittura_corretta = "NO";
$num_linee2++;
} # fine if ($num2 != (count($sub_linee)-1))
else $ultima_linea = $sub_linee[$num2];
} # fine for $num2
} # fine for $num1
if (togli_acapo($linee2[$num_linee2]) != $ultima_linea) $scrittura_corretta = "NO";
if ($scrittura_corretta != "NO") {
@unlink("$nome_file");
if (!rename("$nome_file.tmp","$nome_file")) $scrittura_corretta = "NO";
} # fine if ($scrittura_corretta != "NO")
} # fine if ($fileaperto = fopen("$nome_file.tmp","w+"))
else $scrittura_corretta = "NO";
if ($scrittura_corretta == "NO") {
@unlink("$nome_file.tmp");
echo mex("
ERRORE
 di scrittura del file","funzioni.php")." $nome_file.
";
} # fine if ($scrittura_corretta == "NO")

return $scrittura_corretta;

} # fine function scrivi_file

function crea_lock_file ($nome_file) {

$filelock = fopen("$nome_file.lock","w+");
flock($filelock,2);

return $filelock;

} # fine function crea_lock_file

function distruggi_lock_file ($filelock,$nome_file) {

flock($filelock,3);
fclose($filelock);
@unlink("$nome_file.lock");

} # fine function distruggi_lock_file

function elimina_caratteri_slash ($var) {

$var = str_replace ("'","",$var);
$var = str_replace ("\\","",$var);
$var = str_replace ("\"","",$var);

return $var;

} # fine function elimina_caratteri_slash

function recupera_dati_transazione ($id_transazione,$id_sessione,$anno,$lock_tabletransazioni,&$tipo_transazione,$minuti_durata_sessione="",$cond_sessione="SI",$cond_tipo="NO",$transazioni="transazioni") {

global $PHPR_TAB_PRE;
$tabletransazioni = $PHPR_TAB_PRE.$transazioni;
$tablepersonalizza = $PHPR_TAB_PRE."personalizza";

$tipo_transazione = "";
if ($id_transazione) {
$tabelle_lock = array($tabletransazioni);
if (!$minuti_durata_sessione) $altre_tab_lock = array($tablepersonalizza);
else $altre_tab_lock = array();
if ($lock_tabletransazioni == "SI") $tabelle_lock = lock_tabelle($tabelle_lock,$altre_tab_lock);
if (!$minuti_durata_sessione) {
$minuti_durata_sessione = esegui_query("select valpersonalizza_num from $tablepersonalizza where idpersonalizza = 'minuti_durata_sessione' and idutente = '1'");
$minuti_durata_sessione = risul_query($minuti_durata_sessione,0,'valpersonalizza_num');
} # fine if (!$minuti_durata_sessione)
$limite_transazioni_vecchie = date("Y-m-d H:i:s",(time() - ($minuti_durata_sessione * 60) + (C_DIFF_ORE * 3600)));
if ($cond_tipo != "NO") $cond_tipo = " and tipo_transazione = '$cond_tipo'";
else $cond_tipo = "";
esegui_query("delete from $tabletransazioni where ultimo_accesso <= '$limite_transazioni_vecchie' $cond_tipo");
$id_transazione = aggslashdb($id_transazione);
if ($cond_sessione == "SI") $cond_sessione = " and idsessione = '$id_sessione'";
else $cond_sessione = "";
$dati_transazione = esegui_query("select * from $tabletransazioni where idtransazioni = '$id_transazione' $cond_sessione");
if (numlin_query($dati_transazione) == 1) {
if ($anno == risul_query($dati_transazione,0,'anno')) {
$tipo_transazione = risul_query($dati_transazione,0,'tipo_transazione');
$ultimo_accesso = date("Y-m-d H:i:s",(time() + (C_DIFF_ORE * 3600)));
esegui_query("update $tabletransazioni set ultimo_accesso = '$ultimo_accesso' where idtransazioni = '$id_transazione' $cond_sessione");
} # fine if ($anno == risul_query($dati_transazione,0,'anno'))
} # fine if (numlin_query($dati_transazione) == 1)
if ($lock_tabletransazioni == "SI") unlock_tabelle($tabelle_lock);
} # fine if ($id_transazione)

return $dati_transazione;

} # fine function recupera_dati_transazione

# Function che calcola l'id del periodo corrente per le prenotazioni già iniziate ==> fisse
function calcola_id_periodo_corrente ($anno,$anticipare="SI") {

global $id_utente;
global $PHPR_TAB_PRE;
$tableperiodi = $PHPR_TAB_PRE."periodi".$anno;
if ($anticipare == "SI") {
$tablepersonalizza = $PHPR_TAB_PRE."personalizza";
if ($id_utente == "") $id_utente_anticipa_ore = 1;
else $id_utente_anticipa_ore = $id_utente;
$ore_anticipa_periodo_corrente = esegui_query("select valpersonalizza_num from $tablepersonalizza where idpersonalizza = 'ore_anticipa_periodo_corrente' and idutente = '$id_utente_anticipa_ore'");
$ore_anticipa_periodo_corrente = risul_query($ore_anticipa_periodo_corrente,0,'valpersonalizza_num');
} # fine if ($anticipare == "SI")
else $ore_anticipa_periodo_corrente = 0;
$oggi = date("Y-m-d",(time() + ($ore_anticipa_periodo_corrente * 3600) + (C_DIFF_ORE * 3600)));
$idperiodocorrente = esegui_query("select idperiodi from $tableperiodi where datainizio <= '$oggi' and datafine >= '$oggi' ");
$numidperiodocorrente = numlin_query($idperiodocorrente);
if ($numidperiodocorrente >= 1) {
$num_risposta = 0;
if ($numidperiodocorrente == 2) $num_risposta = 1;
$idperiodocorrente = risul_query($idperiodocorrente,$num_risposta,'idperiodi');
} # fine if ($numidperiodocorrente >= 1)
else {
$annocorrente = date("Y",(time() + (C_DIFF_ORE * 3600)));
if ($anno < $annocorrente) $idperiodocorrente = 100000;
if ($anno >= $annocorrente) $idperiodocorrente = -1;
} # fine else if ($numidperiodocorrente >= 1)

return $idperiodocorrente;

} # fine function calcola_id_periodo_corrente

function mostra_menu_date ($file,$name_date_var,$date_selected,$show_blank_option,$blank_selected,$id_utente,$tema,$standalone_dates_menu="",$second_date_selected="",$js="") {

global $last_dates_menu,$hide_default_dates,$y_ini_menu,$m_ini_menu,$d_ini_menu,$n_dates_menu,$d_increment,$d_names,$m_names,$dates_options_list,$current_dates_menu,$mos_tut_dat,$modifica_pers,$partial_dates;

if ($last_dates_menu != $file) {
$y_ini_menu = "";
$m_ini_menu = "";
$d_ini_menu = "";
$n_dates_menu = "";
$d_increment = "";
$partial_dates = 0;
if (!$standalone_dates_menu) $current_dates_menu = 1;
else $current_dates_menu = 0;
if (substr($file,0,(strlen(C_DATI_PATH) + 15)) == C_DATI_PATH."/selperiodimenu" and $mos_tut_dat == "SI" and $modifica_pers != "NO") include(C_DATI_PATH."/selectperiodi".substr($file,(strlen(C_DATI_PATH) + 15)));
else include("$file");
} # fine if ($last_dates_menu != $file)
else if (!$standalone_dates_menu) $current_dates_menu++;

if ($blank_selected) $date_selected = "";
$num_periodi_date = count($d_increment);
if (($num_periodi_date > 1 or $d_increment[0] > 1) and $date_selected) {
for ($num1 = 0 ; $num1 < $num_periodi_date ; $num1++) {
for ($num2 = 0 ; $num2 < $n_dates_menu[$num1] ; $num2++) {
$data_corr = date("Y-m-d",mktime(0,0,0,($m_ini_menu[$num1] + 1),($d_ini_menu[$num1] + ($num2 * $d_increment[$num1])),$y_ini_menu[$num1]));
if ($data_corr == $date_selected) break;
if ((int) str_replace("-","",$data_corr) > (int) str_replace("-","",$date_selected)) {
if (floor($current_dates_menu / 2) == (($current_dates_menu - 1) / 2)) $date_selected = $data_prec;
else $date_selected = $data_corr;
break;
} # fine if ((int) str_replace("-","",$data_corr) > (int) str_replace("-","",$date_selected))
$data_prec = $data_corr;
} # fine for $num2
if ($data_corr == $date_selected or $data_prec == $date_selected) break;
} # fine for $num1
} # fine if (($num_periodi_date > 1 or $d_increment[0] > 1) and $date_selected)

if ($tema[$id_utente] != "base") include("./themes/".$tema[$id_utente]."/php/selectperiod.php");

if (!$hide_default_dates) {
if (!$js) $out = "<select name=\"$name_date_var\">";
else $out = "<select name=\"'+$name_date_var+'\">";
if ($show_blank_option) $out .= "<option value=\"\"$blank_selected>----</option>";
$out .= str_replace("value=\"$date_selected\">","value=\"$date_selected\" selected>",$dates_options_list);
$out .= "</select>";
if (!$js) echo $out;
else echo "$js += '".str_replace("\n","\\\n",$out)."';
";
} # fine if (!$hide_default_dates)
else unset($dates_options_list);

if (substr($file,0,(strlen(C_DATI_PATH) + 15)) == C_DATI_PATH."/selperiodimenu" and floor($current_dates_menu / 2) != (($current_dates_menu - 1) / 2) and $mos_tut_dat != "SI" and $modifica_pers != "NO" and $partial_dates) {
if (@is_array($_POST)) reset($_POST);
for($num1 = 0 ; $num1 < count($_POST); $num1++) {
if (key($_POST) != "mos_tut_dat" and substr(key($_POST),0,8) != "modifica") $lista_var .= "&".htmlspecialchars(key($_POST))."=".htmlspecialchars(strip_magic_slashs($_POST[key($_POST)]));
next($_POST);
} # fine for $num1
if (@is_array($_GET)) reset($_GET);
for($num1 = 0 ; $num1 < count($_GET); $num1++) {
if (key($_GET) != "mos_tut_dat" and substr(key($_GET),0,8) != "modifica") $lista_var .= "&".htmlspecialchars(key($_GET))."=".htmlspecialchars(strip_magic_slashs($_GET[key($_GET)]));
next($_GET);
} # fine for $num1
if ($lista_var) {
$lista_var = "?mos_tut_dat=SI".$lista_var;
$out = "′";
if (!$js) echo $out;
else echo "$js += '".str_replace("\n","\\\n",$out)."';
";
} # fine if ($lista_var)
} # fine if (substr($file,0,(strlen(C_DATI_PATH) + 15)) == C_DATI_PATH."/selperiodimenu" and floor($current_dates_menu / 2) != (($current_dates_menu - 1) / 2) and...

$last_dates_menu = $file;

} # fine function mostra_menu_date

function allunga_tempo_limite ($n_lim="") {

if (function_exists('set_time_limit')) {
if (!strcmp($n_lim,"")) $n_lim = 420;
$lim_att = 30;
if (function_exists('ini_get')) $lim_att = ini_get('max_execution_time');
if ($lim_att < $n_lim) set_time_limit($n_lim);
} # fine if (function_exists('set_time_limit')

} # fine function allunga_tempo_limite

function http_keep_alive ($car=" ") {

echo $car;
flush();
if (function_exists('ob_flush')) ob_flush();

} # fine function http_keep_alive

/*
function aggiorna_interconnessioni ($nome_funz1,$nome_funz2,$anno,$PHPR_TAB_PRE,$lock) {

$file_interconnessioni = C_DATI_PATH."/dati_interconnessioni.php";
if (@is_file($file_interconnessioni)) {
include($file_interconnessioni);
if (@is_array($ic_present)) {
$interconn_dir = opendir("./includes/interconnect/");
while ($mod_ext = readdir($interconn_dir)) {
if ($mod_ext != "." and $mod_ext != ".." and @is_dir("./includes/interconnect/$mod_ext")) {
include("./includes/interconnect/$mod_ext/name.php");
if ($ic_present[$interconnection_name] == "SI") {
$funz_agg_interconn = $nome_funz1.$interconnection_name;
if (!function_exists($funz_agg_interconn)) include("./includes/interconnect/$mod_ext/functions.php");
$funz_agg_interconn($file_interconnessioni,$anno,$PHPR_TAB_PRE,$lock);
if ($nome_funz2) {
$funz_agg_interconn = $nome_funz2.$interconnection_name;
$funz_agg_interconn($file_interconnessioni,$anno,$PHPR_TAB_PRE,$lock);
} # fine if ($nome_funz2)
} # fine if ($ic_present[$interconnection_name] == "SI")
} # fine if ($modello_ext != "." and $modello_ext != ".." and...
} # fine while ($mod_ext = readdir($interconn_dir))
closedir($interconn_dir);
} # fine if (@is_array($ic_present))
} # fine if (@is_file($file_interconnessioni))

} # fine function aggiorna_interconnessioni
*/

?>


text:
package org.apache.drill.exec.server;

import static org.apache.drill.exec.ExecConstants.SLICE_TARGET;
import static org.apache.drill.exec.planner.physical.PlannerSettings.ENABLE_HASH_AGG_OPTION;
import static org.apache.drill.exec.planner.physical.PlannerSettings.PARTITION_SENDER_SET_THREADS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.io.IOException;

import ch.qos.logback.classic.Level;
import org.apache.commons.math3.util.Pair;
import org.apache.drill.categories.FlakyTest;
import org.apache.drill.exec.client.DrillClient;
import org.apache.drill.exec.physical.impl.partitionsender.PartitionSenderRootExec;
import org.apache.drill.exec.testing.ExecutionControlsInjector;
import org.apache.drill.exec.work.WorkManager;
import org.apache.drill.exec.work.foreman.Foreman;
import org.apache.drill.exec.work.foreman.ForemanException;
import org.apache.drill.exec.work.foreman.ForemanSetupException;
import org.apache.drill.exec.work.foreman.FragmentsRunner;
import org.apache.drill.exec.work.foreman.QueryStateProcessor;
import org.apache.drill.test.BaseTestQuery;
import org.apache.drill.test.ClusterFixture;
import org.apache.drill.test.ClusterFixtureBuilder;
import org.apache.drill.test.ClusterTest;
import org.apache.drill.test.LogFixture;
import org.apache.drill.test.QueryTestUtil;
import org.apache.drill.SingleRowListener;
import org.apache.drill.common.DrillAutoCloseables;
import org.apache.drill.common.concurrent.ExtendedLatch;
import org.apache.drill.common.exceptions.UserException;
import org.apache.drill.common.types.TypeProtos.MinorType;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.ZookeeperTestUtil;
import org.apache.drill.exec.memory.BufferAllocator;
import org.apache.drill.exec.memory.RootAllocatorFactory;
import org.apache.drill.exec.physical.impl.ScreenCreator;
import org.apache.drill.exec.physical.impl.SingleSenderCreator.SingleSenderRootExec;
import org.apache.drill.exec.physical.impl.mergereceiver.MergingRecordBatch;
import org.apache.drill.exec.physical.impl.partitionsender.PartitionerDecorator;
import org.apache.drill.exec.physical.impl.unorderedreceiver.UnorderedReceiverBatch;
import org.apache.drill.exec.physical.impl.xsort.ExternalSortBatch;
import org.apache.drill.exec.planner.sql.DrillSqlWorker;
import org.apache.drill.exec.proto.GeneralRPCProtos.Ack;
import org.apache.drill.exec.proto.UserBitShared.ExceptionWrapper;
import org.apache.drill.exec.proto.UserBitShared.QueryData;
import org.apache.drill.exec.proto.UserBitShared.QueryId;
import org.apache.drill.exec.proto.UserBitShared.QueryResult.QueryState;
import org.apache.drill.exec.proto.UserBitShared.QueryType;
import org.apache.drill.exec.record.BatchSchema;
import org.apache.drill.exec.record.MaterializedField;
import org.apache.drill.exec.record.RecordBatchLoader;
import org.apache.drill.exec.record.VectorWrapper;
import org.apache.drill.exec.rpc.ConnectionThrottle;
import org.apache.drill.exec.rpc.DrillRpcFuture;
import org.apache.drill.exec.rpc.RpcException;
import org.apache.drill.exec.rpc.user.QueryDataBatch;
import org.apache.drill.exec.rpc.user.UserResultsListener;
import org.apache.drill.exec.store.pojo.PojoRecordReader;
import org.apache.drill.exec.testing.Controls;
import org.apache.drill.exec.testing.ControlsInjectionUtil;
import org.apache.drill.exec.util.Pointer;
import org.apache.drill.exec.work.fragment.FragmentExecutor;
import org.apache.drill.categories.SlowTest;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.TestInstantiationException;
import org.slf4j.Logger;

import org.apache.drill.shaded.guava.com.google.common.base.Preconditions;

/**
 *
Test how resilient drillbits are to throwing exceptions during various phases of query
 * execution by injecting exceptions at various points, and to cancellations in various phases.

 *
 * Note: to debug this test case:

 *
use 1000 value for PROBLEMATIC_TEST_NUM_RUNS and possibly NUM_RUNS for RepeatedTest

 *
specify Level.DEBUG for CURRENT_LOG_LEVEL

 *
compare trace output for successful test case and failed

 */
@Tag(SlowTest.TAG)
@Tag(FlakyTest.TAG)
public class TestDrillbitResilience extends ClusterTest {
  private static final Logger logger = org.slf4j.LoggerFactory.getLogger(TestDrillbitResilience.class);
  protected static LogFixture logFixture;

  /**
   * The number of times test should be repeated. For proper testing this functionality set this value to 1000
   */
  private static final int NUM_RUNS = 3;
  private static final int PROBLEMATIC_TEST_NUM_RUNS = 3;
  private static final int TIMEOUT = 15;
  private final static Level CURRENT_LOG_LEVEL = Level.DEBUG;

  /**
   * Note: Counting sys.memory executes a fragment on every drillbit. This is a better check in comparison to
   * counting sys.drillbits.
   */
  private static final String TEST_QUERY = "select * from sys.memory";

  /*
   * Canned drillbit names.
   */
  private final static String DRILLBIT_ALPHA = "alpha";
  private final static String DRILLBIT_BETA = "beta";
  private final static String DRILLBIT_GAMMA = "gamma";

  @BeforeAll
  public static void startSomeDrillbits() throws Exception {
    logFixture = LogFixture.builder()
      .toConsole()
      .logger(TestDrillbitResilience.class, CURRENT_LOG_LEVEL)
      .logger(DrillClient.class, CURRENT_LOG_LEVEL)
      .logger(QueryStateProcessor.class, CURRENT_LOG_LEVEL)
      .logger(WorkManager.class, CURRENT_LOG_LEVEL)
      .logger(UnorderedReceiverBatch.class, CURRENT_LOG_LEVEL)
      .logger(ExtendedLatch.class, CURRENT_LOG_LEVEL)
      .logger(Foreman.class, CURRENT_LOG_LEVEL)
      .logger(QueryStateProcessor.class, CURRENT_LOG_LEVEL)
      .logger(ExecutionControlsInjector.class, CURRENT_LOG_LEVEL)
      .build();
    ZookeeperTestUtil.setJaasTestConfigFile();
    dirTestWatcher.start(TestDrillbitResilience.class); // until DirTestWatcher is implemented for JUnit5
    ClusterFixtureBuilder builder = ClusterFixture.builder(dirTestWatcher)
      .configProperty(ExecConstants.HTTP_ENABLE, false) // turn off the HTTP server to avoid port conflicts between the drill bits
      .withBits(DRILLBIT_ALPHA, DRILLBIT_BETA, DRILLBIT_GAMMA);
    startCluster(builder);
    clearAllInjections();
    logger.debug("Start 3 drillbits Test Drill cluster: {}, {}, {}", DRILLBIT_ALPHA, DRILLBIT_BETA, DRILLBIT_GAMMA);
  }

  @AfterAll
  public static void tearDownAfterClass() throws Exception {
    logFixture.close();
  }

  /**
   * Clear all injections.
   */
  private static void clearAllInjections() {
    logger.debug("Clear all injections");
    Preconditions.checkNotNull(client);
    ControlsInjectionUtil.clearControls(client.client());
  }

  /**
   * Check that all the drillbits are ok.
   *

   *
The current implementation does this by counting the number of drillbits using a query.
   */
  private static void assertDrillbitsOk() {
    SingleRowListener listener = new SingleRowListener() {
      private final BufferAllocator bufferAllocator = RootAllocatorFactory.newRoot(cluster.config());
      private final RecordBatchLoader loader = new RecordBatchLoader(bufferAllocator);

      @Override
      public void rowArrived(QueryDataBatch queryResultBatch) {
        // load the single record
        final QueryData queryData = queryResultBatch.getHeader();
        loader.load(queryData.getDef(), queryResultBatch.getData());
        assertEquals(1, loader.getRecordCount());

        // there should only be one column
        final BatchSchema batchSchema = loader.getSchema();
        assertEquals(1, batchSchema.getFieldCount());

        // the column should be an integer
        final MaterializedField countField = batchSchema.getColumn(0);
        final MinorType fieldType = countField.getType().getMinorType();
        assertEquals(MinorType.BIGINT, fieldType);

        // get the column value
        final VectorWrapper<?> vw = loader.iterator().next();
        final Object obj = vw.getValueVector().getAccessor().getObject(0);
        assertTrue(obj instanceof Long);
        final Long countValue = (Long) obj;

        // assume this means all the drillbits are still ok
        assertEquals(cluster.drillbits().size(), countValue.intValue());

        loader.clear();
      }

      @Override
      public void cleanup() {
        loader.clear();
        DrillAutoCloseables.closeNoChecked(bufferAllocator);
      }
    };

    try {
      QueryTestUtil.testWithListener(client.client(), QueryType.SQL, "select count(*) from sys.memory", listener);
      listener.waitForCompletion();
      QueryState state = listener.getQueryState();
      assertSame(state, QueryState.COMPLETED, () -> String.format("QueryState should be COMPLETED (and not %s).", state));
      assertTrue(listener.getErrorList().isEmpty(), "There should not be any errors when checking if Drillbits are OK");
    } catch (final Exception e) {
      throw new RuntimeException("Couldn't query active drillbits", e);
    } finally {
      logger.debug("Cleanup listener");
      listener.cleanup();
    }
    logger.debug("Drillbits are ok.");
  }

  @BeforeEach
  void setUp(TestInfo testInfo) {
    String testName = testInfo.getTestMethod().orElseThrow(() -> new TestInstantiationException("Can't get method neme")).getName();
    String testOrRepetitionName = testInfo.getDisplayName();
    if(testOrRepetitionName.startsWith("repetition")) {
      logger.debug("{} for {} test started", testOrRepetitionName, testName);
    } else {
      logger.debug("{} test started", testName);
    }
  }

  @AfterEach
  public void checkDrillbits(TestInfo testInfo) {
    clearAllInjections(); // so that the drillbit check itself doesn't trigger anything
    assertDrillbitsOk(); // TODO we need a way to do this without using a query
    String testName = testInfo.getTestMethod().orElseThrow(() -> new TestInstantiationException("Can't get method neme")).getName();
    String testOrRepetitionName = testInfo.getDisplayName();
    if(testOrRepetitionName.startsWith("repetition")) {
      logger.debug("{} for {} test finished", testOrRepetitionName, testName);
    } else {
      logger.debug("{} test finished", testName);
    }
  }

  @Test
  @Timeout(value = TIMEOUT)
  public void settingNoOpInjectionsAndQuery() {
    final long before = countAllocatedMemory();

    final String controls = Controls.newBuilder()
      .addExceptionOnBit(getClass(), "noop", RuntimeException.class, cluster.drillbit(DRILLBIT_BETA).getContext().getEndpoint())
      .build();
    setControls(controls);
    final WaitUntilCompleteListener listener = new WaitUntilCompleteListener();
    QueryTestUtil.testWithListener(client.client(), QueryType.SQL, TEST_QUERY, listener);
    final Pair<QueryState, Exception> pair = listener.waitForCompletion();
    assertStateCompleted(pair, QueryState.COMPLETED);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  @RepeatedTest(NUM_RUNS)
  @Timeout(value = TIMEOUT)
  public void foreman_runTryBeginning() {
    final long before = countAllocatedMemory();

    testForeman("run-try-beginning");

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  @RepeatedTest(PROBLEMATIC_TEST_NUM_RUNS) // for more info: DRILL-3163, DRILL-3167, DRILL-7973, DRILL-8030
  @Timeout(value = TIMEOUT)
  public void foreman_runTryEnd() {
    final long before = countAllocatedMemory();

    testForeman("run-try-end");

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  @Test // To test pause and resume. Test hangs and times out if resume did not happen.
  @Timeout(value = TIMEOUT)
  public void passThrough() {
    final long before = countAllocatedMemory();

    final WaitUntilCompleteListener listener = new WaitUntilCompleteListener() {
      @Override
      public void queryIdArrived(final QueryId queryId) {
        super.queryIdArrived(queryId);
        final ExtendedLatch trigger = new ExtendedLatch(1);
        (new ResumingThread(queryId, ex, trigger)).start();
        trigger.countDown();
      }
    };

    final String controls = Controls.newBuilder()
      .addPause(PojoRecordReader.class, "read-next")
      .build();
    setControls(controls);

    QueryTestUtil.testWithListener(client.client(), QueryType.SQL, TEST_QUERY, listener);
    final Pair<QueryState, Exception> result = listener.waitForCompletion();
    assertStateCompleted(result, QueryState.COMPLETED);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  // DRILL-2383: Cancellation TC 1: cancel before any result set is returned.
  @RepeatedTest(PROBLEMATIC_TEST_NUM_RUNS) // for more info: DRILL-3052, DRILL-3192
  @Timeout(value = TIMEOUT)
  public void cancelWhenQueryIdArrives() {
    final long before = countAllocatedMemory();

    final WaitUntilCompleteListener listener = new WaitUntilCompleteListener() {

      @Override
      public void queryIdArrived(final QueryId queryId) {
        super.queryIdArrived(queryId);
        cancelAndResume();
      }
    };

    final String controls = Controls.newBuilder()
      .addPause(FragmentExecutor.class, "fragment-running")
      .build();
    assertCancelledWithoutException(controls, listener);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  // DRILL-2383: Cancellation TC 2: cancel in the middle of fetching result set
  @RepeatedTest(PROBLEMATIC_TEST_NUM_RUNS) // for more info: DRILL-6228, DRILL-8030
  @Timeout(value = TIMEOUT)
  public void cancelInMiddleOfFetchingResults() {
    final long before = countAllocatedMemory();

    final WaitUntilCompleteListener listener = new WaitUntilCompleteListener() {
      private boolean cancelRequested = false;

      @Override
      public void dataArrived(final QueryDataBatch result, final ConnectionThrottle throttle) {
        if (!cancelRequested) {
          check(queryId != null, "Query id should not be null, since we have waited long enough.");
          cancelAndResume();
          cancelRequested = true;
        }
        result.release();
      }
    };

    // skip once i.e. wait for one batch, so that #dataArrived above triggers #cancelAndResume
    final String controls = Controls.newBuilder()
      .addPause(ScreenCreator.class, "sending-data", 1)
      .build();
    assertCancelledWithoutException(controls, listener);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  // DRILL-2383: Cancellation TC 3: cancel after all result set are produced but not all are fetched
  @RepeatedTest(PROBLEMATIC_TEST_NUM_RUNS) // for more info: DRILL-6228, DRILL-8030
  @Timeout(value = TIMEOUT)
  public void cancelAfterAllResultsProduced() {
    final long before = countAllocatedMemory();

    final WaitUntilCompleteListener listener = new WaitUntilCompleteListener() {

      @Override
      public void dataArrived(final QueryDataBatch result, final ConnectionThrottle throttle) {
        if (lastDrillbit()) {
          check(queryId != null, "Query id should not be null, since we have waited long enough.");
          cancelAndResume();
        }
        result.release();
      }
    };

    final String controls = Controls.newBuilder()
      .addPause(ScreenCreator.class, "send-complete")
      .build();
    assertCancelledWithoutException(controls, listener);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  // DRILL-2383: Cancellation TC 4: cancel after everything is completed and fetched
  @RepeatedTest(PROBLEMATIC_TEST_NUM_RUNS) // for more info: DRILL-3967, DRILL-7973
  @Timeout(value = TIMEOUT)
  public void cancelAfterEverythingIsCompleted() {
    final long before = countAllocatedMemory();

    final WaitUntilCompleteListener listener = new WaitUntilCompleteListener() {

      @Override
      public void dataArrived(final QueryDataBatch result, final ConnectionThrottle throttle) {
        if (lastDrillbit()) {
          check(queryId != null, "Query id should not be null, since we have waited long enough.");
          // need to wait until all batches are processed, since foreman-cleanup - the pause that happened earlier,
          // than the client accepts queryCompleted() from UserResultsListener
          cancelAndResume();
        }
        result.release();
      }
    };

    final String controls = Controls.newBuilder()
      .addPause(Foreman.class, "foreman-cleanup")
      .build();
    assertCompletedWithoutException(controls, listener); // changed from CANCELLED

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  @Test // DRILL-2383: Completion TC 1: success
  @Timeout(value = TIMEOUT)
  public void successfullyCompletes() {
    final long before = countAllocatedMemory();

    final WaitUntilCompleteListener listener = new WaitUntilCompleteListener();
    QueryTestUtil.testWithListener(client.client(), QueryType.SQL, TEST_QUERY, listener);
    final Pair<QueryState, Exception> result = listener.waitForCompletion();
    assertStateCompleted(result, QueryState.COMPLETED);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  @Test // DRILL-2383: Completion TC 2: failed query - before query is executed - while sql parsing
  @Timeout(value = TIMEOUT)
  public void failsWhenParsing() {
    final long before = countAllocatedMemory();

    final String exceptionDesc = "sql-parsing";
    final Class<? extends Throwable> exceptionClass = ForemanSetupException.class;
    // Inject the failure twice since there can be retry after first failure introduced in DRILL-6762. Retry is because
    // of version mismatch in local and remote function registry which syncs up lazily.
    final String controls = Controls.newBuilder()
      .addException(DrillSqlWorker.class, exceptionDesc, exceptionClass, 0, 2)
      .build();
    assertFailsWithException(controls, exceptionClass, exceptionDesc, TEST_QUERY);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  @Test // DRILL-2383: Completion TC 3: failed query - before query is executed, while sending fragments to other drillbits
  @Timeout(value = TIMEOUT)
  public void failsWhenSendingFragments() {
    final long before = countAllocatedMemory();

    final String exceptionDesc = "send-fragments";
    final Class<? extends Throwable> exceptionClass = ForemanException.class;
    final String controls = Controls.newBuilder()
      .addException(FragmentsRunner.class, exceptionDesc, exceptionClass)
      .build();
    assertFailsWithException(controls, exceptionClass, exceptionDesc, TEST_QUERY);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  @Test // DRILL-2383: Completion TC 4: failed query - during query execution
  @Timeout(value = TIMEOUT)
  public void failsDuringExecution() {
    final long before = countAllocatedMemory();

    final String exceptionDesc = "fragment-execution";
    final Class<? extends Throwable> exceptionClass = IOException.class;
    final String controls = Controls.newBuilder()
      .addException(FragmentExecutor.class, exceptionDesc, exceptionClass)
      .build();
    assertFailsWithException(controls, exceptionClass, exceptionDesc, TEST_QUERY);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  /**
   * Test canceling query interrupts currently blocked FragmentExecutor threads waiting for some event to happen.
   * Specifically tests canceling fragment which has {@link MergingRecordBatch} blocked waiting for data.
   */
  @RepeatedTest(NUM_RUNS)
  @Timeout(value = TIMEOUT)
  public void interruptingBlockedMergingRecordBatch() {
    final long before = countAllocatedMemory();

    final String control = Controls.newBuilder()
      .addPause(MergingRecordBatch.class, "waiting-for-data", 1)
      .build();
    interruptingBlockedFragmentsWaitingForData(control);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  /**
   * Test canceling query interrupts currently blocked FragmentExecutor threads waiting for some event to happen.
   * Specifically tests canceling fragment which has {@link UnorderedReceiverBatch} blocked waiting for data.
   */
  @RepeatedTest(PROBLEMATIC_TEST_NUM_RUNS)
  @Timeout(value = TIMEOUT)
  public void interruptingBlockedUnorderedReceiverBatch() {
    final long before = countAllocatedMemory();

    final String control = Controls.newBuilder()
      .addPause(UnorderedReceiverBatch.class, "waiting-for-data", 1)
      .build();
    logger.debug("Start interruptingBlockedFragmentsWaitingForData");
    interruptingBlockedFragmentsWaitingForData(control);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  /**
   * Tests interrupting the fragment thread that is running {@link PartitionSenderRootExec}.
   * {@link PartitionSenderRootExec} spawns threads for partitioner. Interrupting fragment thread should also interrupt
   * the partitioner threads.
   */
  @RepeatedTest(NUM_RUNS)
  @Timeout(value = TIMEOUT)
  public void interruptingPartitionerThreadFragment() {
    try {
      client.alterSession(SLICE_TARGET, "1");
      client.alterSession(ENABLE_HASH_AGG_OPTION, "true");
      client.alterSession(PARTITION_SENDER_SET_THREADS.getOptionName(), "6");

      final long before = countAllocatedMemory();

      final String controls = Controls.newBuilder()
      .addLatch(PartitionerDecorator.class, "partitioner-sender-latch")
      .addPause(PartitionerDecorator.class, "wait-for-fragment-interrupt", 1)
      .build();

      final String query = "SELECT sales_city, COUNT(*) cnt FROM cp.`region.json` GROUP BY sales_city";
      assertCancelledWithoutException(controls, new ListenerThatCancelsQueryAfterFirstBatchOfData(), query);

      final long after = countAllocatedMemory();
      assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
    } finally {
      client.resetSession(SLICE_TARGET);
      client.resetSession(ENABLE_HASH_AGG_OPTION);
      client.resetSession(PARTITION_SENDER_SET_THREADS.getOptionName());
    }
  }

  @RepeatedTest(PROBLEMATIC_TEST_NUM_RUNS) // for more info: DRILL-3193, DRILL-7973
  @Timeout(value = TIMEOUT)
  public void interruptingWhileFragmentIsBlockedInAcquiringSendingTicket() {
    final long before = countAllocatedMemory();

    final String control = Controls.newBuilder()
      .addPause(SingleSenderRootExec.class, "data-tunnel-send-batch-wait-for-interrupt", 1)
      .build();
    assertCancelledWithoutException(control, new ListenerThatCancelsQueryAfterFirstBatchOfData());

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  @RepeatedTest(PROBLEMATIC_TEST_NUM_RUNS)
  @Timeout(value = TIMEOUT)
  public void memoryLeaksWhenCancelled() {
    client.alterSession(SLICE_TARGET, "10");

    final long before = countAllocatedMemory();

    try {
      final String controls = Controls.newBuilder()
        .addPause(ScreenCreator.class, "sending-data", 1)
        .build();
      String query = null;
      try {
        query = BaseTestQuery.getFile("queries/tpch/09.sql");
        query = query.substring(0, query.length() - 1); // drop the ";"
      } catch (final IOException e) {
        fail("Failed to get query file", e);
      }

      final WaitUntilCompleteListener listener = new WaitUntilCompleteListener() {
        private volatile boolean cancelRequested = false;

        @Override
        public void dataArrived(final QueryDataBatch result, final ConnectionThrottle throttle) {
          if (!cancelRequested) {
            check(queryId != null, "Query id should not be null, since we have waited long enough.");
            cancelAndResume();
            cancelRequested = true;
          }
          result.release();
        }
      };

      assertCancelledWithoutException(controls, listener, query);

      final long after = countAllocatedMemory();
      assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
    } finally {
      client.resetSession(SLICE_TARGET);
    }
  }

  @RepeatedTest(NUM_RUNS) // for more info: DRILL-3194, DRILL-7973
  @Timeout(value = TIMEOUT)
  public void memoryLeaksWhenFailed() {
    client.alterSession(SLICE_TARGET, "10");

    final long before = countAllocatedMemory();

    try {
      final String exceptionDesc = "fragment-execution";
      final Class<? extends Throwable> exceptionClass = IOException.class;
      final String controls = Controls.newBuilder()
        .addException(FragmentExecutor.class, exceptionDesc, exceptionClass)
        .build();

      String query = null;
      try {
        query = BaseTestQuery.getFile("queries/tpch/09.sql");
        query = query.substring(0, query.length() - 1); // drop the ";"
      } catch (final IOException e) {
        fail("Failed to get query file: " + e);
      }

      assertFailsWithException(controls, exceptionClass, exceptionDesc, query);

      final long after = countAllocatedMemory();
      assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));

    } finally {
      client.resetSession(SLICE_TARGET);
    }
  }

  @Test
  @Timeout(value = TIMEOUT) // for more info: DRILL-3065
  public void failsAfterMSorterSorting() {

    // Note: must use an input table that returns more than one
    // batch. The sort uses an optimization for single-batch inputs
    // which bypasses the code where this partiucular fault is
    // injected.

    final String query = "select n_name from cp.`tpch/lineitem.parquet` order by n_name";
    final Class<? extends Exception> typeOfException = RuntimeException.class;

    final long before = countAllocatedMemory();
    final String controls = Controls.newBuilder()
      .addException(ExternalSortBatch.class, ExternalSortBatch.INTERRUPTION_AFTER_SORT, typeOfException)
      .build();
    assertFailsWithException(controls, typeOfException, ExternalSortBatch.INTERRUPTION_AFTER_SORT, query);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  @Test
  @Timeout(value = TIMEOUT) // for more info: DRILL-3085
  public void failsAfterMSorterSetup() {

    // Note: must use an input table that returns more than one
    // batch. The sort uses an optimization for single-batch inputs
    // which bypasses the code where this partiucular fault is
    // injected.

    final String query = "select n_name from cp.`tpch/lineitem.parquet` order by n_name";
    final Class<? extends Exception> typeOfException = RuntimeException.class;

    final long before = countAllocatedMemory();
    final String controls = Controls.newBuilder()
    .addException(ExternalSortBatch.class, ExternalSortBatch.INTERRUPTION_AFTER_SETUP, typeOfException)
      .build();
    assertFailsWithException(controls, typeOfException, ExternalSortBatch.INTERRUPTION_AFTER_SETUP, query);

    final long after = countAllocatedMemory();
    assertEquals(before, after, () -> String.format("We are leaking %d bytes", after - before));
  }

  /**
   * Tests can use this listener to wait, until the submitted query completes or fails, by
   * calling #waitForCompletion.
   */
  private static class WaitUntilCompleteListener implements UserResultsListener {
    protected final ExtendedLatch latch = new ExtendedLatch(1); // to signal completion
    protected QueryId queryId = null;
    protected volatile Pointer<Exception> ex = new Pointer<>();
    protected volatile QueryState state = null;
    private int count = 0;

    /**
     * Method that sets the exception if the condition is not met.
     */
    protected final void check(final boolean condition, final String format, final Object... args) {
      if (!condition) {
        ex.value = new IllegalStateException(String.format(format, args));
      }
    }

    /**
     * Method that cancels and resumes the query, in order.
     */
    protected final void cancelAndResume() {
      Preconditions.checkNotNull(queryId);
      final ExtendedLatch trigger = new ExtendedLatch(1);
      (new CancellingThread(queryId, ex, trigger)).start();
      (new ResumingThread(queryId, ex, trigger)).start();
    }

    @Override
    public void queryIdArrived(final QueryId queryId) {
      this.queryId = queryId;
    }

    @Override
    public void submissionFailed(final UserException ex) {
      this.ex.value = ex;
      state = QueryState.FAILED;
      latch.countDown();
    }

    @Override
    public void queryCompleted(final QueryState state) {
      this.state = state;
      latch.countDown();
    }

    @Override
    public void dataArrived(final QueryDataBatch result, final ConnectionThrottle throttle) {
      result.release();
    }

    public final Pair<QueryState, Exception> waitForCompletion() {
      try {
        logger.debug("Wait for completion. latch: {}", latch.getCount());
        latch.await(); // awaitUninterruptibly method usage here prevents JUnit timeout work
      } catch (InterruptedException e) {
        logger.error("Interrupted while waiting for event latch");
      }
      logger.debug("Completed. Wait finished");
      return new Pair<>(state, ex.value);
    }

    /**
     * It is useful for queries returned the data from all drillbits. Use this method to make sure {@link #dataArrived}
     * returns the data from every drillbit
     *
     * @return true, in case current listener methods return results from last drillbit already
     */
    boolean lastDrillbit() {
      return ++count == cluster.drillbits().size();
    }
  }

  private static class ListenerThatCancelsQueryAfterFirstBatchOfData extends WaitUntilCompleteListener {
    private boolean cancelRequested = false;

    @Override
    public void dataArrived(final QueryDataBatch result, final ConnectionThrottle throttle) {
      if (!cancelRequested) {
        logger.debug("First batch arrived, so cancelling thread started");
        check(queryId != null, "Query id should not be null, since we have waited long enough.");
        (new CancellingThread(queryId, ex, null)).start();
        cancelRequested = true;
      }
      result.release();
    }
  }

  /**
   * Thread that cancels the given query id. After the cancel is acknowledged, the latch is counted down.
   */
  private static class CancellingThread extends Thread {
    private final QueryId queryId;
    private final Pointer<Exception> ex;
    private final ExtendedLatch latch;

    public CancellingThread(QueryId queryId, Pointer<Exception> ex, ExtendedLatch latch) {
      this.queryId = queryId;
      this.ex = ex;
      this.latch = latch;
      logger.debug("Cancelling thread created");
    }

    @Override
    public void run() {
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        logger.debug("Cancelling thread interrupted. Ignore it");
        // just ignore
      }
      logger.debug("Cancelling {} query started", queryId);
      final DrillRpcFuture<Ack> cancelAck = client.client().cancelQuery(queryId);
      logger.debug("Check future: {}", cancelAck);
      try {
        Ack ack = cancelAck.checkedGet();
        logger.debug("Sleep thread for 0.01 seconds");
        Thread.sleep(10);
        logger.debug("Ack: {}", ack);
      } catch (RpcException ex) {
        this.ex.value = ex;
        logger.debug("The query wasn't canceled." + ex);
      } catch (InterruptedException e) {
        logger.debug("Sleep thread interrupted. Ignore it");
        // just ignore
      }
      if (latch != null) {
        latch.countDown();
      }
      logger.debug("Finish cancelling thread");
    }
  }

  /**
   * Thread that resumes the given query id. After the latch is counted down, the resume signal is sent, until then
   * the thread waits without interruption.
   */
  private static class ResumingThread extends Thread {
    private final QueryId queryId;
    private final Pointer<Exception> ex;
    private final ExtendedLatch latch;

    public ResumingThread(final QueryId queryId, final Pointer<Exception> ex, final ExtendedLatch latch) {
      this.queryId = queryId;
      this.ex = ex;
      this.latch = latch;
      logger.debug("Cancelling thread created");
    }

    @Override
    public void run() {
      latch.awaitUninterruptibly();
      final DrillRpcFuture<Ack> resumeAck = client.client().resumeQuery(queryId);
      try {
        resumeAck.checkedGet();
      } catch (final RpcException ex) {
        this.ex.value = ex;
      }
    }
  }

  /**
   * Given the result of {@link WaitUntilCompleteListener#waitForCompletion},
   * this method fails if the completed state is not as expected, or if an
   * exception is thrown. The completed state could be COMPLETED or CANCELED.
   * This state is set when {@link WaitUntilCompleteListener#queryCompleted} is
   * called.
   */
  private void assertStateCompleted(final Pair<QueryState, Exception> result, final QueryState expectedState) {
    final QueryState actualState = result.getFirst();
    final Exception exception = result.getSecond();
    if (actualState != expectedState || exception != null) {
      fail(String.format("Query state is incorrect (expected: %s, actual: %s) AND/OR \nException thrown: %s",
        expectedState, actualState, exception == null ? "none." : exception));
    }
  }

  /**
   * Given a set of controls, this method ensures that the given query completes with a {@link QueryState#CANCELED} state.

   */
  private void assertCancelledWithoutException(final String controls, final WaitUntilCompleteListener listener,
                                                      final String query) {
    setControls(controls);

    QueryTestUtil.testWithListener(client.client(), QueryType.SQL, query, listener);
    final Pair<QueryState, Exception> result = listener.waitForCompletion();
    assertStateCompleted(result, QueryState.CANCELED);
  }

  /**
   * Given a set of controls, this method ensures that the given query completes with a {@link QueryState#COMPLETED} state.

   * {@link QueryState#COMPLETED} is a terminal state and can't be canceled.
   * See more: {@link org.apache.drill.exec.work.foreman.QueryStateProcessor#cancel}
   */
  private void assertCompletedWithoutException(final String controls, final WaitUntilCompleteListener listener) {
    setControls(controls);

    QueryTestUtil.testWithListener(client.client(), QueryType.SQL, TEST_QUERY, listener);
    assertStateCompleted(listener.waitForCompletion(), QueryState.COMPLETED);
  }

  /**
   * Given a set of controls, this method ensures that the TEST_QUERY completes with a CANCELED state.
   */
  private void assertCancelledWithoutException(final String controls, final WaitUntilCompleteListener listener) {
    assertCancelledWithoutException(controls, listener, TEST_QUERY);
  }

  private long countAllocatedMemory() {
    // wait to make sure all fragments finished cleaning up
    try {
      logger.debug("Sleep thread for 2 seconds");
      Thread.sleep(1500); // 1500
    } catch (InterruptedException e) {
      logger.debug("Sleep thread interrupted. Ignore it", e);
      // just ignore
    }

    long allocated = 0;
    for (Drillbit drillbit : cluster.drillbits()) {
      allocated += drillbit.getContext().getAllocator().getAllocatedMemory();
    }
    logger.debug("Allocated memory: " + allocated);
    return allocated;
  }

  private void interruptingBlockedFragmentsWaitingForData(final String control) {
    try {
      client.alterSession(SLICE_TARGET, "1");
      client.alterSession(ENABLE_HASH_AGG_OPTION, "false");

      final String query = "SELECT sales_city, COUNT(*) cnt FROM cp.`region.json` GROUP BY sales_city";
      assertCancelledWithoutException(control, new ListenerThatCancelsQueryAfterFirstBatchOfData(), query);
    } finally {
      client.resetSession(SLICE_TARGET);
      client.resetSession(ENABLE_HASH_AGG_OPTION);
    }
  }

  /**
   * Given a set of controls, this method ensures TEST_QUERY fails with the given class and desc.
   */
  private void assertFailsWithException(final String controls, final Class<? extends Throwable> exceptionClass,
                                               final String exceptionDesc, final String query) {
    setControls(controls);
    final WaitUntilCompleteListener listener = new WaitUntilCompleteListener();
    QueryTestUtil.testWithListener(client.client(), QueryType.SQL, query, listener);
    final Pair<QueryState, Exception> result = listener.waitForCompletion();
    final QueryState state = result.getFirst();
    assertSame(state, QueryState.FAILED, () -> String.format("Query state should be FAILED (and not %s).", state));
    assertExceptionMessage(result.getSecond(), exceptionClass, exceptionDesc);
  }

  /**
   * The same as {@link #assertFailsWithException}, but also allows COMPLETED state for the query.

   * Note: in some cases we are completing the query faster than run-try-end exception is injecetd and thrown in
   * Foreman. The completed state is fine for such cases
   */
  private void assertFailsOrCompletedWithException(final String controls, final Class<? extends Throwable> exceptionClass,
                                        final String exceptionDesc, final String query) {
    setControls(controls);
    final WaitUntilCompleteListener listener = new WaitUntilCompleteListener();
    QueryTestUtil.testWithListener(client.client(), QueryType.SQL, query, listener);
    final Pair<QueryState, Exception> result = listener.waitForCompletion();
    final QueryState state = result.getFirst();

    assertTrue(state.equals(QueryState.FAILED) || state.equals(QueryState.COMPLETED),
      () -> String.format("Query state should be FAILED (and not %s).", state));
    assertExceptionMessage(result.getSecond(), exceptionClass, exceptionDesc);
  }

  /**
   * Test throwing exceptions from sites within the Foreman class, as specified by the site
   * description
   *
   * @param desc site description
   */
  private void testForeman(final String desc) {
    final String controls = Controls.newBuilder()
      .addException(Foreman.class, desc, ForemanException.class)
      .build();
    assertFailsOrCompletedWithException(controls, ForemanException.class, desc, TEST_QUERY);
  }

  /**
   * Set the given controls.
   */
  private void setControls(final String controls) {
    ControlsInjectionUtil.setControls(client.client(), controls);
  }

  /**
   * Check that the injected exception is what we were expecting.
   *
   * @param throwable      the throwable that was caught (by the test)
   * @param exceptionClass the expected exception class
   * @param desc           the expected exception site description
   */
  private void assertExceptionMessage(final Throwable throwable, final Class<? extends Throwable> exceptionClass,
                                      final String desc) {
    assertTrue(throwable instanceof UserException, "Throwable was not of UserException type");
    final ExceptionWrapper cause = ((UserException) throwable).getOrCreatePBError(false).getException();
    assertEquals(exceptionClass.getName(), cause.getExceptionClass(), "Exception class names should match");
    assertEquals(desc, cause.getMessage(), "Exception sites should match.");
  }
}

redpajama_set_name: RedPajamaGithub


text:
import { environment } from 'src/environments/environment';
import { mockModules, mockProviders, devModules, devProviders } from './config';

const { databaseEnabled } = environment;

export const extModules = databaseEnabled ? devModules : mockModules;
export const exProviders = databaseEnabled ? devProviders : mockProviders;


text:
	if [[ ! -f /etc/apt/sources.list.original ]] && \
		[[ -n $ubuntu_mirror ]];
	then
		cp /etc/apt/sources.list /etc/apt/sources.list.original
		sed \
			"s/us.archive.ubuntu.com/$ubuntu_mirror/" \
			< /etc/apt/sources.list.original \
			> /etc/apt/sources.list
	else
		echo "Repository already configured to $ubuntu_mirror"
	fi

## Time Zone

	if [[ -n $time_zone ]];
	then
		echo $time_zone > /etc/timezone
		dpkg-reconfigure --frontend noninteractive tzdata
	fi

## Update and Upgrade

	# Get update-success-stamp file last modified
	last_update_raw=$(stat -c %y /var/lib/apt/periodic/update-success-stamp)

	# Extract the date
	last_update_cooked=${last_update_raw:0:10}

	# Get today's date
	today=$(date --rfc-3339=date)

	# if last update was not today
	if [[ $last_update_cooked != $today ]];
	then
		# run update
		apt-get -y update

		# run upgrade
		DEBIAN_FRONTEND=noninteractive \
			apt-get -y \
			-o Dpkg::Options::="--force-confdef" \
			-o Dpkg::Options::="--force-confold" \
			upgrade
	else
		echo "apt-get update and apt-get upgrade have already been run today ($last_update_cooked)"
	fi


text:
#ifndef ART_COMPILER_OPTIMIZING_REMOVE_UNUSED_LOOPS_H_
#define ART_COMPILER_OPTIMIZING_REMOVE_UNUSED_LOOPS_H_

#include "optimization_x86.h"

namespace art {

class HRemoveUnusedLoops : public HOptimization_X86 {
 public:
  explicit HRemoveUnusedLoops(HGraph* graph, OptimizingCompilerStats* stats = nullptr)
      : HOptimization_X86(graph, kRemoveUnusedLoopsPassName, stats) {}

  void Run() OVERRIDE;

 private:
  static constexpr const char* kRemoveUnusedLoopsPassName = "remove_unused_loops";

  bool CheckInstructionsInBlock(HLoopInformation_X86* loop_info, HBasicBlock* loop_block);
  bool CheckPhisInBlock(HLoopInformation_X86* loop_info, HBasicBlock* loop_block);
  void RemoveLoop(HLoopInformation_X86* loop_info,
                  HBasicBlock*pre_header,
                  HBasicBlock* exit_block);
  void UpdateExternalPhis();

  std::set<HPhi*> external_loop_phis_;

  DISALLOW_COPY_AND_ASSIGN(HRemoveUnusedLoops);
};

}  // namespace art

#endif  // ART_COMPILER_OPTIMIZING_REMOVE_UNUSED_LOOPS_H_


text:
namespace base {

namespace {

// Created a time value based on |year|, |month| and |day_of_month| parameters.
Time CreateTimeFromParams(int year, int month, int day_of_month) {
  DCHECK_GT(year, 1970);
  DCHECK_GT(month, 0);
  DCHECK_LT(month, 13);
  DCHECK_GT(day_of_month, 0);
  DCHECK_LT(day_of_month, 32);

  Time::Exploded exploded;
  exploded.year = year;
  exploded.month = month;
  exploded.day_of_week = 0;  // Should be unused.
  exploded.day_of_month = day_of_month;
  exploded.hour = 0;
  exploded.minute = 0;
  exploded.second = 0;
  exploded.millisecond = 0;

  return Time::FromLocalExploded(exploded);
}

}  // namespace

static const char kHistogramFieldTrialSeparator('_');

// statics
const int FieldTrial::kNotFinalized = -1;
const int FieldTrial::kDefaultGroupNumber = 0;
bool FieldTrial::enable_benchmarking_ = false;

const char FieldTrialList::kPersistentStringSeparator('/');
int FieldTrialList::kExpirationYearInFuture = 0;

//------------------------------------------------------------------------------
// FieldTrial methods and members.

FieldTrial::FieldTrial(const std::string& name,
                       const Probability total_probability,
                       const std::string& default_group_name)
    : name_(name),
      divisor_(total_probability),
      default_group_name_(default_group_name),
      random_(static_cast<Probability>(divisor_ * RandDouble())),
      accumulated_group_probability_(0),
      next_group_number_(kDefaultGroupNumber + 1),
      group_(kNotFinalized),
      enable_field_trial_(true),
      forced_(false) {
  DCHECK_GT(total_probability, 0);
  DCHECK(!name_.empty());
  DCHECK(!default_group_name_.empty());
}

FieldTrial::EntropyProvider::~EntropyProvider() {
}

void FieldTrial::UseOneTimeRandomization() {
  // No need to specify randomization when the group choice was forced.
  if (forced_)
    return;
  DCHECK_EQ(group_, kNotFinalized);
  DCHECK_EQ(kDefaultGroupNumber + 1, next_group_number_);
  const EntropyProvider* entropy_provider =
      FieldTrialList::GetEntropyProviderForOneTimeRandomization();
  if (!entropy_provider) {
    NOTREACHED();
    Disable();
    return;
  }

  random_ = static_cast<Probability>(
      divisor_ * entropy_provider->GetEntropyForTrial(name_));
}

void FieldTrial::Disable() {
  enable_field_trial_ = false;

  // In case we are disabled after initialization, we need to switch
  // the trial to the default group.
  if (group_ != kNotFinalized) {
    // Only reset when not already the default group, because in case we were
    // forced to the default group, the group number may not be
    // kDefaultGroupNumber, so we should keep it as is.
    if (group_name_ != default_group_name_)
      SetGroupChoice(default_group_name_, kDefaultGroupNumber);
  }
}

int FieldTrial::AppendGroup(const std::string& name,
                            Probability group_probability) {
  // When the group choice was previously forced, we only need to return the
  // the id of the chosen group, and anything can be returned for the others.
  if (forced_) {
    DCHECK(!group_name_.empty());
    if (name == group_name_) {
      return group_;
    }
    DCHECK_NE(next_group_number_, group_);
    // We still return different numbers each time, in case some caller need
    // them to be different.
    return next_group_number_++;
  }

  DCHECK_LE(group_probability, divisor_);
  DCHECK_GE(group_probability, 0);

  if (enable_benchmarking_ || !enable_field_trial_)
    group_probability = 0;

  accumulated_group_probability_ += group_probability;

  DCHECK_LE(accumulated_group_probability_, divisor_);
  if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
    // This is the group that crossed the random line, so we do the assignment.
    SetGroupChoice(name, next_group_number_);
    FieldTrialList::NotifyFieldTrialGroupSelection(name_, group_name_);
  }
  return next_group_number_++;
}

int FieldTrial::group() {
  if (group_ == kNotFinalized) {
    accumulated_group_probability_ = divisor_;
    // Here it's OK to use kDefaultGroupNumber
    // since we can't be forced and not finalized.
    DCHECK(!forced_);
    SetGroupChoice(default_group_name_, kDefaultGroupNumber);
    FieldTrialList::NotifyFieldTrialGroupSelection(name_, group_name_);
  }
  return group_;
}

std::string FieldTrial::group_name() {
  group();  // call group() to make sure group assignment was done.
  DCHECK(!group_name_.empty());
  return group_name_;
}

bool FieldTrial::GetSelectedGroup(SelectedGroup* selected_group) {
  if (group_ == kNotFinalized)
    return false;
  selected_group->trial = name_;
  selected_group->group = group_name_;
  return true;
}

// static
std::string FieldTrial::MakeName(const std::string& name_prefix,
                                 const std::string& trial_name) {
  std::string big_string(name_prefix);
  big_string.append(1, kHistogramFieldTrialSeparator);
  return big_string.append(FieldTrialList::FindFullName(trial_name));
}

// static
void FieldTrial::EnableBenchmarking() {
  DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
  enable_benchmarking_ = true;
}

void FieldTrial::SetForced() {
  // We might have been forced before (e.g., by CreateFieldTrial) and it's
  // first come first served, e.g., command line switch has precedence.
  if (forced_)
    return;
  // Explicit forcing should only be for cases where we want to set the group
  // probabilities before the hard coded field trial setup is executed. So
  // there must have been at least one non-default group appended at that point.
  DCHECK_GT(next_group_number_, kDefaultGroupNumber + 1);

  // And we must finalize the group choice before we mark ourselves as forced.
  group();
  forced_ = true;
}

FieldTrial::~FieldTrial() {}

void FieldTrial::SetGroupChoice(const std::string& name, int number) {
  group_ = number;
  if (name.empty())
    StringAppendF(&group_name_, "%d", group_);
  else
    group_name_ = name;
  DVLOG(1) << "Field trial: " << name_ << " Group choice:" << group_name_;
}

//------------------------------------------------------------------------------
// FieldTrialList methods and members.

// static
FieldTrialList* FieldTrialList::global_ = NULL;

// static
bool FieldTrialList::used_without_global_ = false;

FieldTrialList::Observer::~Observer() {
}

FieldTrialList::FieldTrialList(
    const FieldTrial::EntropyProvider* entropy_provider)
    : application_start_time_(TimeTicks::Now()),
      entropy_provider_(entropy_provider),
      observer_list_(new ObserverListThreadSafe<FieldTrialList::Observer>(
          ObserverListBase<FieldTrialList::Observer>::NOTIFY_EXISTING_ONLY)) {
  DCHECK(!global_);
  DCHECK(!used_without_global_);
  global_ = this;

  Time::Exploded exploded;
  Time two_years_from_now =
      Time::NowFromSystemTime() + TimeDelta::FromDays(730);
  two_years_from_now.LocalExplode(&exploded);
  kExpirationYearInFuture = exploded.year;
}

FieldTrialList::~FieldTrialList() {
  AutoLock auto_lock(lock_);
  while (!registered_.empty()) {
    RegistrationList::iterator it = registered_.begin();
    it->second->Release();
    registered_.erase(it->first);
  }
  DCHECK_EQ(this, global_);
  global_ = NULL;
}

// static
FieldTrial* FieldTrialList::FactoryGetFieldTrial(
    const std::string& name,
    FieldTrial::Probability total_probability,
    const std::string& default_group_name,
    const int year,
    const int month,
    const int day_of_month,
    int* default_group_number) {
  if (default_group_number)
    *default_group_number = FieldTrial::kDefaultGroupNumber;
  // Check if the field trial has already been created in some other way.
  FieldTrial* existing_trial = Find(name);
  if (existing_trial) {
    CHECK(existing_trial->forced_);
    // If the field trial has already been forced, check whether it was forced
    // to the default group. Return the chosen group number, in that case..
    if (default_group_number &&
        default_group_name == existing_trial->default_group_name()) {
      *default_group_number = existing_trial->group();
    }
    return existing_trial;
  }

  FieldTrial* field_trial =
      new FieldTrial(name, total_probability, default_group_name);
  if (GetBuildTime() > CreateTimeFromParams(year, month, day_of_month))
    field_trial->Disable();
  FieldTrialList::Register(field_trial);
  return field_trial;
}

// static
FieldTrial* FieldTrialList::Find(const std::string& name) {
  if (!global_)
    return NULL;
  AutoLock auto_lock(global_->lock_);
  return global_->PreLockedFind(name);
}

// static
int FieldTrialList::FindValue(const std::string& name) {
  FieldTrial* field_trial = Find(name);
  if (field_trial)
    return field_trial->group();
  return FieldTrial::kNotFinalized;
}

// static
std::string FieldTrialList::FindFullName(const std::string& name) {
  FieldTrial* field_trial = Find(name);
  if (field_trial)
    return field_trial->group_name();
  return "";
}

// static
bool FieldTrialList::TrialExists(const std::string& name) {
  return Find(name) != NULL;
}

// static
void FieldTrialList::StatesToString(std::string* output) {
  DCHECK(output->empty());
  if (!global_)
    return;
  AutoLock auto_lock(global_->lock_);

  for (RegistrationList::iterator it = global_->registered_.begin();
       it != global_->registered_.end(); ++it) {
    const std::string& name = it->first;
    std::string group_name = it->second->group_name_internal();
    if (group_name.empty())
      continue;  // Should not include uninitialized trials.
    DCHECK_EQ(name.find(kPersistentStringSeparator), std::string::npos);
    DCHECK_EQ(group_name.find(kPersistentStringSeparator), std::string::npos);
    output->append(name);
    output->append(1, kPersistentStringSeparator);
    output->append(group_name);
    output->append(1, kPersistentStringSeparator);
  }
}

// static
void FieldTrialList::GetFieldTrialSelectedGroups(
    FieldTrial::SelectedGroups* selected_groups) {
  DCHECK(selected_groups->empty());
  if (!global_)
    return;
  AutoLock auto_lock(global_->lock_);

  for (RegistrationList::iterator it = global_->registered_.begin();
       it != global_->registered_.end(); ++it) {
    FieldTrial::SelectedGroup selected_group;
    if (it->second->GetSelectedGroup(&selected_group))
      selected_groups->push_back(selected_group);
  }
}

// static
bool FieldTrialList::CreateTrialsFromString(const std::string& trials_string) {
  DCHECK(global_);
  if (trials_string.empty() || !global_)
    return true;

  size_t next_item = 0;
  while (next_item < trials_string.length()) {
    size_t name_end = trials_string.find(kPersistentStringSeparator, next_item);
    if (name_end == trials_string.npos || next_item == name_end)
      return false;
    size_t group_name_end = trials_string.find(kPersistentStringSeparator,
                                               name_end + 1);
    if (group_name_end == trials_string.npos || name_end + 1 == group_name_end)
      return false;
    std::string name(trials_string, next_item, name_end - next_item);
    std::string group_name(trials_string, name_end + 1,
                           group_name_end - name_end - 1);
    next_item = group_name_end + 1;

    if (!CreateFieldTrial(name, group_name))
      return false;
  }
  return true;
}

// static
FieldTrial* FieldTrialList::CreateFieldTrial(
    const std::string& name,
    const std::string& group_name) {
  DCHECK(global_);
  DCHECK_GE(name.size(), 0u);
  DCHECK_GE(group_name.size(), 0u);
  if (name.empty() || group_name.empty() || !global_)
    return NULL;

  FieldTrial* field_trial = FieldTrialList::Find(name);
  if (field_trial) {
    // In single process mode, or when we force them from the command line,
    // we may have already created the field trial.
    if (field_trial->group_name_internal() != group_name)
      return NULL;
    return field_trial;
  }
  const int kTotalProbability = 100;
  field_trial = new FieldTrial(name, kTotalProbability, group_name);
  // This is where we may assign a group number different from
  // kDefaultGroupNumber to the default group.
  field_trial->AppendGroup(group_name, kTotalProbability);
  field_trial->forced_ = true;
  FieldTrialList::Register(field_trial);
  return field_trial;
}

// static
void FieldTrialList::AddObserver(Observer* observer) {
  if (!global_)
    return;
  DCHECK(global_);
  global_->observer_list_->AddObserver(observer);
}

// static
void FieldTrialList::RemoveObserver(Observer* observer) {
  if (!global_)
    return;
  DCHECK(global_);
  global_->observer_list_->RemoveObserver(observer);
}

// static
void FieldTrialList::NotifyFieldTrialGroupSelection(
    const std::string& name,
    const std::string& group_name) {
  if (!global_)
    return;
  DCHECK(global_);
  global_->observer_list_->Notify(
      &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
      name,
      group_name);
}

// static
size_t FieldTrialList::GetFieldTrialCount() {
  if (!global_)
    return 0;
  AutoLock auto_lock(global_->lock_);
  return global_->registered_.size();
}

// static
const FieldTrial::EntropyProvider*
    FieldTrialList::GetEntropyProviderForOneTimeRandomization() {
  if (!global_) {
    used_without_global_ = true;
    return NULL;
  }

  return global_->entropy_provider_.get();
}

FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
  RegistrationList::iterator it = registered_.find(name);
  if (registered_.end() == it)
    return NULL;
  return it->second;
}

// static
void FieldTrialList::Register(FieldTrial* trial) {
  if (!global_) {
    used_without_global_ = true;
    return;
  }
  AutoLock auto_lock(global_->lock_);
  DCHECK(!global_->PreLockedFind(trial->name()));
  trial->AddRef();
  global_->registered_[trial->name()] = trial;
}

}  // namespace base


text:
#if LESSTHAN_NET35
extern alias nunitlinq;
#endif

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
//
// Authors:
//      Federico Di Gregorio <fog@initd.org>

using System;
using System.Linq.Expressions;
using NUnit.Framework;

#if LESSTHAN_NETCOREAPP20 || LESSTHAN_NETSTANDARD20

using System.Reflection;

#endif

namespace MonoTests.System.Linq.Expressions
{
    [TestFixture]
    public class ExpressionTestDivide
    {
        [Test]
        public void Arg1Null()
        {
            Assert.Throws<ArgumentNullException>(() => Expression.Divide(null, Expression.Constant(1)));
        }

        [Test]
        public void Arg2Null()
        {
            Assert.Throws<ArgumentNullException>(() => Expression.Divide(Expression.Constant(1), null));
        }

        [Test]
        public void ArgTypesDifferent()
        {
            Assert.Throws<InvalidOperationException>(() => Expression.Divide(Expression.Constant(1), Expression.Constant(2.0)));
        }

        [Test]
        public void Boolean()
        {
            Assert.Throws<InvalidOperationException>(() => Expression.Divide(Expression.Constant(true), Expression.Constant(false)));
        }

        [Test]
        public void NoOperatorClass()
        {
            Assert.Throws<InvalidOperationException>(() => Expression.Divide(Expression.Constant(new NoOpClass()), Expression.Constant(new NoOpClass())));
        }

        [Test]
        public void Nullable()
        {
            int? a = 1;
            int? b = 2;

            var expr = Expression.Divide(Expression.Constant(a), Expression.Constant(b));
            Assert.AreEqual(ExpressionType.Divide, expr.NodeType, "Divide#05");
            Assert.AreEqual(typeof(int), expr.Type, "Divide#06");
            Assert.IsNull(expr.Method, "Divide#07");
            Assert.AreEqual("(1 / 2)", expr.ToString(), "Divide#08");
        }

        [Test]
        public void Numeric()
        {
            var expr = Expression.Divide(Expression.Constant(1), Expression.Constant(2));
            Assert.AreEqual(ExpressionType.Divide, expr.NodeType, "Divide#01");
            Assert.AreEqual(typeof(int), expr.Type, "Divide#02");
            Assert.IsNull(expr.Method, "Divide#03");
            Assert.AreEqual("(1 / 2)", expr.ToString(), "Divide#04");
        }

        [Test]
        public void UserDefinedClass()
        {
            // We can use the simplest version of GetMethod because we already know only one
            // exists in the very simple class we're using for the tests.
            var method = typeof(OpClass).GetMethod("op_Division");

            var expr = Expression.Divide(Expression.Constant(new OpClass()), Expression.Constant(new OpClass()));
            Assert.AreEqual(ExpressionType.Divide, expr.NodeType, "Divide#09");
            Assert.AreEqual(typeof(OpClass), expr.Type, "Divide#10");
            Assert.AreEqual(method, expr.Method, "Divide#11");
            Assert.AreEqual
            (
                "(value(MonoTests.System.Linq.Expressions.OpClass) / value(MonoTests.System.Linq.Expressions.OpClass))",
                expr.ToString(), "Divide#13"
            );
        }
    }
}


text:
/**
 * JUnit helper classes and TestRules.
 * @see org.junit.rules.TestRule
 */
package org.apache.logging.log4j.junit;