<?php

session_start();
ob_start();
###################################
## cpanel Configuration
$cpanelUrl = "https://gt4host.com:2083"; // cPanel URL
$cpanelUser = "sawatime"; // Your cPanel username
$apiToken = "B2WXLF0S0EOM86Y0E66OLOK69U2BK1JI"; // API token created in cPanel
// cPanel API URL for UAPI
$uapiBase = "/execute/Mysql/";
##################################
## user coming data
// Get database details from POST request
$dbName = $_POST['dbName']; // Shortened database name
$dbUser = $_POST['dbUser']; // Shortened username for the database
$dbPassword = $_POST['dbPassword']; // Alphanumeric password
$dbHost = "localhost"; // Database host (assuming localhost)
###################################
## Paths
$zipFile = '../../_versions/' . $_POST['versionName']; // The zip file
$extractTo = '../../' . $_POST['newerpFilename']; // for the new versions choose folder name where the contents will be extracted
$syncStructurePath = $extractTo . '/__db/syncStructure.sql'; // Absolute path to the SQL file
$pathToConnection = $extractTo . '/models/sql/ConnectionProperty.class.php'; //Absolute path
$pathToDBName = $extractTo . '/views/default/archiveview/dbNames.txt'; //Absolute path
#################################
//get the do the action
$do = $_GET['do'];
$filesCount = $foldersCount = $currentFile = $allTotal = 0;



## step 1
if ($do == "createdb") {
    // Create database, user, and assign privileges
    createDatabase($dbName);
    createDbUser($dbUser, $dbPassword);
    addUserToDatabase($dbUser, $dbName);
}
## step 2
else if ($do == "extract") {//unzip
    $operationType = (int) $_POST['operationType'];
    if ($operationType == 1) {//updating existing program archive it first
        $extractTo = $source_dir = dirname(getcwd()); // The folder where the contents will be extracted
        $destination_dir = dirname(dirname(getcwd())) . '/_tempArchives/' . basename(dirname(getcwd())) . ' - archived at ' . date('Y-m-d H:i:s');
        ## Paths
        $syncStructurePath = $extractTo . '/__db/syncStructure.sql'; // Absolute path to the SQL file
        $pathToConnection = $extractTo . '/models/sql/ConnectionProperty.class.php'; //Absolute path
        $pathToDBName = $extractTo . '/views/default/archiveview/dbNames.txt'; //Absolute path
        #################################
        move_folder($source_dir, $destination_dir);
    }
    // Create the folder if it doesn't exist
    if (!is_dir($extractTo)) {
        mkdir($extractTo, 0755, true);
    }
    ############################
    //program unzip files
    $zip = new ZipArchive;
    if ($zip->open($zipFile) === TRUE) {
        $totalFiles = $zip->numFiles; // Get total number of files in the archive
        $currentFile = 0;
        for ($i = 0; $i < $totalFiles; $i++) {
            $file = $zip->getNameIndex($i); // Get the file name at the given index
            $zip->extractTo($extractTo, $file); // Extract this specific file
            $currentFile++;
            // Send progress update for each file extracted
            sendProgressUnzip($currentFile, $totalFiles, $file);
            sleep(.1); // Simulate a delay (can be removed in production)
        }

        $zip->close();
        setConnectionOnFiles($operationType);

        sendProgressUnzip($totalFiles, $totalFiles, 'Unzipping completed successfully.');
        //echo 'Unzipping completed successfully!';
    } else {
        sendProgressUnzip(0, $totalFiles, 'Failed to unzip the file.');
        //echo 'Failed to unzip the file.';
    }
}
## step 3
else if ($do == "handeledb") {
    $operationType = (int) $_POST['operationType'];
    // Get database details from POST request
    if ($operationType == 1) {//update version i already have the righr name
        $extractTo = $source_dir = dirname(getcwd()); // The folder where the contents will be extracted
        ## Paths
        $syncStructurePath = $extractTo . '/__db/syncStructure.sql'; // Absolute path to the SQL file
        $pathToConnection = $extractTo . '/models/sql/ConnectionProperty.class.php'; //Absolute path
        $pathToDBName = $extractTo . '/views/default/archiveview/dbNames.txt'; //Absolute path
        #################################
        ## first take db backup
        $done = backup_tables('*', '../../_tempArchives/', $dbName, $dbHost, $dbUser, $dbPassword);
        if ($done == 1) {
            sendProgressDB('Backup DB', 0);
        } else {
            sendProgressDB('Backup error', 0);
            exit;
        }
    } else {
        $dbName = $cpanelUser . "_" . $dbName; // Shortened database name
        $dbUser = $cpanelUser . "_" . $dbUser; // Shortened username for the database
    }

    // Connect to MySQL database
    $mysqli = new mysqli($dbHost, $dbUser, $dbPassword, $dbName);

    if ($mysqli->connect_error) {
        sendProgressDB('Connection failed: ' . $mysqli->connect_error, 0);
        exit;
    }

    if ($operationType == 1) {//update version i already have the righr name
    } else {
        // Step 1: Retrieve all the table names
        $tablesResult = $mysqli->query("SHOW TABLES");
        if (!$tablesResult) {
            sendProgressDB('Error retrieving tables: ' . $mysqli->error, 0);
            exit;
        }

        $tables = [];
        while ($row = $tablesResult->fetch_array()) {
            $tables[] = $row[0];  // Each row contains one table name
        }

        // Step 2: Drop all tables in the database
        foreach ($tables as $table) {
            $dropQuery = "DROP TABLE IF EXISTS `$table`";
            if (!$mysqli->query($dropQuery)) {
                sendProgressDB('Error dropping table ' . $table . ': ' . $mysqli->error, 0);
                exit;
            }
            sendProgressDB("Dropped table: $table", 10); // Update progress for each dropped table
        }
    }


    // Step 3: Check if the SQL file exists
    if (!file_exists($syncStructurePath)) {
        sendProgressDB('SQL file not found.' . $syncStructurePath, 0);
        exit;
    }


    // Read the SQL file
    $sqlContent = file_get_contents($syncStructurePath);

    // Break SQL into smaller parts for execution
    $queries = explode(";", $sqlContent);
    $totalQueries = count($queries);
    $queriesExecuted = 0;

    sendProgressDB('Starting execution of SQL file...', 0);

    // Execute queries in batches
    foreach ($queries as $query) {
        $query = trim($query);
        if (!empty($query)) {
            // Check for ALTER TABLE ADD COLUMN and make sure the column doesn't already exist
            if (preg_match('/ALTER TABLE\s+`?(\w+)`?\s+ADD\s+`?(\w+)`?/i', $query, $matches)) {
                $tableName = $matches[1];
                $columnName = $matches[2];

                // Check if the column already exists
                $columnExistsQuery = "SHOW COLUMNS FROM `$tableName` LIKE '$columnName'";
                $result = $mysqli->query($columnExistsQuery);
                if ($result && $result->num_rows > 0) {
                    sendProgressDB("Skipping query: Column `$columnName` already exists in table `$tableName`.", ($queriesExecuted / $totalQueries) * 100);
                    continue; // Skip the query if the column already exists
                }
            }

            // Execute the query
            if ($mysqli->multi_query($query . ';')) {
                do {
                    if ($result = $mysqli->store_result()) {
                        $result->free();
                    }
                } while ($mysqli->more_results() && $mysqli->next_result());
            } else {
                // Capture the error and the query that caused it
                $error = $mysqli->error;
                if (strpos($error, 'Duplicate entry') !== false && $operationType == 1) {
                    //skip it
                    sendProgressDB("Skipping query: Duplicate entry <br> Query: <code>$query</code>", ($queriesExecuted / $totalQueries) * 100);
                } else {
                    sendProgressDB("Error executing query: $error <br> Query: <code>$query</code>", ($queriesExecuted / $totalQueries) * 100);
                    exit; // Exit if there's an error
                }
            }

            // Update progress
            $queriesExecuted++;
            $percent = ($queriesExecuted / $totalQueries) * 100;
            sendProgressDB("Executed $queriesExecuted/$totalQueries queries.", $percent);
        }
    }

    $mysqli->close();

    // Final update on completion
    sendProgressDB('SQL execution completed successfully!', 100);
}
##
elseif ($do == "removeOldBackup") {
    $filesBackups = glob('../../_tempArchives/' . basename(dirname(getcwd())) . '*');
    foreach ($filesBackups as $value) {
        deleteFolder($value);
    }

    $dbBackups = glob('../../_tempArchives/' . $_SESSION['dbname'] . '*');
    foreach ($dbBackups as $value) {
        unlink($value);
    }
    echo 1;
} elseif ($do == "restoreOldBackupFiles") {
    $progFileName = basename(dirname(getcwd()));
    $order = 'desc';
    ############################################################################
    ## step 1 files
    ## 1- get last files backup
    $filesBackups = glob('../../_tempArchives/' . $progFileName . '*', GLOB_ONLYDIR);
    usort($filesBackups, function($a, $b) use ($order) {
        $a = basename($a);
        $b = basename($b);
        $dateA = strtotime(explode('.', str_replace($progFileName, "", $a))[0]);
        $dateB = strtotime(explode('.', str_replace($progFileName, "", $b))[0]);
        if ($order == 'ASC') {
            return $dateA - $dateB;
        } else {
            return $dateB - $dateA;
        }
    });
    $lastFileDir = $filesBackups[0]; //the backup we will restore dir
    $lastFile = basename($filesBackups[0]); //the backup we will restore file name
    $newFolderName = basename(dirname(getcwd())); //current codes file name
    $newFolderdir = dirname(getcwd()); //current codes file path
    $source_dir = '../../_tempArchives/' . $lastFile;
    $destination_dir = dirname(dirname(getcwd()));



    if (isset($lastFile) && !empty($lastFile)) {
        # count Files And Folders in source , destination
        $filesCount = $foldersCount = 0;
        countFilesAndFolders($lastFileDir);
        $totalFilesToMove = $filesCount + $foldersCount;

        $filesCount = $foldersCount = 0;
        countFilesAndFolders($newFolderdir);
        $totalFilesToRemove = $filesCount + $foldersCount;

        $allTotal = $totalFilesToMove + $totalFilesToRemove;
        $currentFile = 0;
        ## 2 - remove current dir & make new empty folder with same name
        deleteFolder(dirname(getcwd()), 1);
        @mkdir($newFolderdir);
        ## 3 - move archive folder out of _tempArchives folder
        move_folder($source_dir, $destination_dir . "/" . $newFolderName, 1);
    } else {
        sendProgressUnzip(0, 1, ' ..... no backup exist check again ..... ');
    }
} elseif ($do == "restoreOldBackupDB") {
    $order = 'desc';
    $versionsDirPath = dirname(dirname(getcwd())) . '/_tempArchives';
    ############################################################################
    ## step 2 db
    ## 1- get last db backup
    //$sqlFiles = glob($path . '/{*.sql,*.sql.gz,*.sql.bz2}', GLOB_BRACE);
    $dbBackups = glob('../../_tempArchives/' . $_SESSION['dbname'] . '*.sql');
    usort($dbBackups, function($a, $b) use ($order) {
        $a = basename($a);
        $b = basename($b);
        $dateA = strtotime(explode('.', str_replace("++", " ", str_replace($_SESSION['dbname'], "", $a)))[0]);
        $dateB = strtotime(explode('.', str_replace("++", " ", str_replace($_SESSION['dbname'], "", $b)))[0]);
        if ($order == 'ASC') {
            return $dateA - $dateB;
        } else {
            return $dateB - $dateA;
        }
    });
    $lastDB = basename($dbBackups[0]);
    $lastDBFullPath = $syncStructurePath = dirname($dbBackups[0]) . "/" . $lastDB;
    if (isset($lastDB) && !empty($lastDB)) {
        ## 2- get connection data
        $dbHost = 'localhost';
        $pathToConnection = '../models/sql/ConnectionProperty.class.php'; //Absolute path
        $handle = fopen($pathToConnection, "r");
        if ($handle) {
            $dbUser = '';
            $dbPassword = '';
            $dbName = $_SESSION['dbname'];
            while (($line = fgets($handle)) !== false) {
                if (strpos($line, 'private static $user') !== false) {
                    $dbUser = explode("'", $line)[1];
                } else if (strpos($line, 'private static $password') !== false) {
                    $dbPassword = explode("'", $line)[1];
                }
            }
            fclose($handle);
        }
        // Connect to MySQL database
        $mysqli = new mysqli($dbHost, $dbUser, $dbPassword, $dbName);

        if ($mysqli->connect_error) {
            sendProgressDB('Connection failed: ' . $mysqli->connect_error, 0);
            exit;
        }


        // Step 1: Retrieve all the table names
        $tablesResult = $mysqli->query("SHOW TABLES");
        if (!$tablesResult) {
            sendProgressDB('Error retrieving tables: ' . $mysqli->error, 0);
            exit;
        }

        $tables = [];
        while ($row = $tablesResult->fetch_array()) {
            $tables[] = $row[0];  // Each row contains one table name
        }

        // Step 2: Drop all tables in the database
        $tablescount = count($tables);
        $i = 0;
        foreach ($tables as $table) {
            $dropQuery = "DROP TABLE IF EXISTS `$table`";
            if (!$mysqli->query($dropQuery)) {
                sendProgressDB('Error dropping table ' . $table . ': ' . $mysqli->error, 0);
                exit;
            }
            $i++;
            sendProgressDB("Step1 - empty current DB - Dropped table: $table", ($i / $tablescount) * 100); // Update progress for each dropped table
        }


        // Step 3: Check if the SQL file exists
        if (!file_exists($syncStructurePath)) {
            sendProgressDB('SQL file not found.' . $syncStructurePath, 0);
            exit;
        }


        // Read the SQL file
        $sqlContent = file_get_contents($syncStructurePath);

        // Break SQL into smaller parts for execution
        $queries = explode(";", $sqlContent);
        $totalQueries = count($queries);
        $queriesExecuted = 0;

        sendProgressDB('Step2 restore backup - Starting execution of SQL file...', 0);

        // Execute queries in batches
        foreach ($queries as $query) {
            $query = trim($query);
            if (!empty($query)) {
                // Check for ALTER TABLE ADD COLUMN and make sure the column doesn't already exist
                if (preg_match('/ALTER TABLE\s+`?(\w+)`?\s+ADD\s+`?(\w+)`?/i', $query, $matches)) {
                    $tableName = $matches[1];
                    $columnName = $matches[2];

                    // Check if the column already exists
                    $columnExistsQuery = "SHOW COLUMNS FROM `$tableName` LIKE '$columnName'";
                    $result = $mysqli->query($columnExistsQuery);
                    if ($result && $result->num_rows > 0) {
                        sendProgressDB("Skipping query: Column `$columnName` already exists in table `$tableName`.", ($queriesExecuted / $totalQueries) * 100);
                        continue; // Skip the query if the column already exists
                    }
                }

                // Execute the query
                if ($mysqli->multi_query($query . ';')) {
                    do {
                        if ($result = $mysqli->store_result()) {
                            $result->free();
                        }
                    } while ($mysqli->more_results() && $mysqli->next_result());
                } else {
                    // Capture the error and the query that caused it
                    $error = $mysqli->error;
                    if (strpos($error, 'Duplicate entry') !== false && $operationType == 1) {
                        //skip it
                        sendProgressDB("Skipping query: Duplicate entry <br> Query: <code>$query</code>", ($queriesExecuted / $totalQueries) * 100);
                    } else {
                        sendProgressDB("Error executing query: $error <br> Query: <code>$query</code>", ($queriesExecuted / $totalQueries) * 100);
                        exit; // Exit if there's an error
                    }
                }

                // Update progress
                $queriesExecuted++;
                $percent = ($queriesExecuted / $totalQueries) * 100;
                sendProgressDB("Step2 restore backup - Executed $queriesExecuted/$totalQueries queries.", $percent);
            }
        }

        $mysqli->close();

        // Final update on completion
        sendProgressDB('SQL execution completed successfully!', 100);
        unlink($lastDBFullPath);
    } else {
        sendProgressDB(' ..... no backup exist check again ..... ', 0);
    }
}
/* -- create db functions --------------------------------------------------- */

function createDatabase($dbName) {
    global $cpanelUrl, $cpanelUser, $uapiBase;

    $dbName = $cpanelUser . "_" . $dbName; // cPanel prefixes the database name
    $url = $cpanelUrl . $uapiBase . "create_database?name=$dbName";
    $response = callCpanelAPI($url);

    if (isset($response['status']) && $response['status'] == 1) {
        echo "Database '$dbName' created successfully.\n";
    } else {
        echo "Error creating database: " . print_r($response, true) . "\n"; // Log full response
    }
}

function createDbUser($dbUser, $dbPassword) {
    global $cpanelUrl, $cpanelUser, $uapiBase;

    $dbUser = $cpanelUser . "_" . $dbUser; // cPanel prefixes the username
    $url = $cpanelUrl . $uapiBase . "create_user?name=$dbUser&password=$dbPassword";
    $response = callCpanelAPI($url);

    if (isset($response['status']) && $response['status'] == 1) {
        echo "Database user '$dbUser' created successfully.\n";
    } else {
        echo "Error creating user: " . print_r($response, true) . "\n"; // Log full response
    }
}

function addUserToDatabase($dbUser, $dbName) {
    global $cpanelUrl, $cpanelUser, $uapiBase;

    $dbName = $cpanelUser . "_" . $dbName;
    $dbUser = $cpanelUser . "_" . $dbUser;
    $url = $cpanelUrl . $uapiBase . "set_privileges_on_database?user=$dbUser&database=$dbName&privileges=ALL";
    $response = callCpanelAPI($url);

    if (isset($response['status']) && $response['status'] == 1) {
        echo "User '$dbUser' granted all privileges on database '$dbName'.\n";
    } else {
        echo "Error assigning privileges: " . print_r($response, true) . "\n"; // Log full response
    }
}

/* -------------------------------------------------------------------------- */
/* -- extract functions ----------------------------------------------------- */

function setConnectionOnFiles($operationType) {
    global $cpanelUser;
    global $extractTo;
    global $dbName;
    global $dbUser;
    global $dbPassword;
    global $pathToConnection;
    global $pathToDBName;

    // Get database details from POST request
    if ($operationType == 1) {//update version i already have the righr name
    } else {
        $dbName = $cpanelUser . "_" . $dbName; // Shortened database name
        $dbUser = $cpanelUser . "_" . $dbUser; // Shortened username for the database
    }
    $dbPassword = $_POST['dbPassword']; // Alphanumeric password
    ###########################################
    ##update dbname file
    // Open and truncate the file
    $fh = fopen($pathToDBName, 'w');
    fclose($fh);


    $fh = fopen($pathToDBName, 'w'); // Open and truncate the file
    fwrite($fh, $dbName);
    fclose($fh);

    ###########################################
    ##update connection data
    $connectionFileTxt = '';
    $handle = fopen($pathToConnection, "r");
    if ($handle) {
        $flag = 0;
        while (($line = fgets($handle)) !== false) {
            if ($flag != 1) {
                if (strpos($line, 'private static $user') !== false) {
                    $connectionFileTxt .= ' private static $user = ' . "'" . $dbUser . "';" . PHP_EOL;
                } else if (strpos($line, 'private static $password') !== false) {
                    $connectionFileTxt .= ' private static $password = ' . "'" . $dbPassword . "';" . PHP_EOL;
                } else if (strpos($line, 'private static $database') !== false) {
                    $connectionFileTxt .= ' private static $database = ' . "'" . $dbName . "';" . PHP_EOL;
                } else if (strpos($line, 'return ConnectionProperty::$database = ') !== false && strpos($line, '$_SESSION') === false) {
                    $connectionFileTxt .= ' return ConnectionProperty::$database = ' . "'" . $dbName . "';" . PHP_EOL;
                    $connectionFileTxt .= "             \$_SESSION['dbname'] = " . "'" . $dbName . "';" . PHP_EOL;
                    $flag = 1;
                } else {
                    $connectionFileTxt .= $line;
                }
            } else {
                $flag = 0;
                continue; // skip this line i have already add it at 4th if
            }
        }

        fclose($handle);
    }


    // Open and truncate the file
    $fh = fopen($pathToConnection, 'w');
    fclose($fh);


    $fh = fopen($pathToConnection, 'w'); // Open and truncate the file
    fwrite($fh, $connectionFileTxt);
    fclose($fh);
}

/* -------------------------------------------------------------------------- */
/* -- common functions ------------------------------------------------------ */

function callCpanelAPI($url) {
    global $cpanelUser, $apiToken;

    $headers = [
        "Authorization: cpanel $cpanelUser:$apiToken"
    ];

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        echo "Curl error: " . curl_error($ch) . "\n"; // Log curl error
        return [];
    }

    curl_close($ch);
    return json_decode($response, true);
}

// Function to send progress updates for each file
function sendProgressUnzip($currentFile, $totalFiles, $file) {
    echo "<script>parent.updateProgressUnzip($currentFile,$totalFiles, '$file');</script>";
    ob_flush();
    flush();
}

function sendProgressDB($message, $percent) {
    sleep(.1); // Simulate a delay (can be removed in production)
    $escapedMessage = addslashes($message);
    echo "<script>parent.updateProgressDB('$escapedMessage', $percent);</script>";
    ob_flush();
    flush();
}

/* -------------------------------------------------------------------------- */

function backup_tables($tables, $backupdir, $dbname, $db_host, $db_user, $db_password) {

    $root = $db_user;
    $host = $db_host;
    $passd = $db_password;

    //getcwd() is to Gets the current working directory
    $partition = explode(":", getcwd())[0]; //$generalSettings->partition;
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
        //do nothing
    } else { //if (!empty(exec("ip link"))) {// unix, linux, mac
        $partition = 0;
    }

    if (empty($partition) || $partition == "0") { //linux
        $inrtoi = $backupdir . $dbname . "_archivedAt" . date("Y-m-d++H:i:s") . ".sql";
        sendProgressDB($inrtoi, 10);
        ##/usr/bin/mysqldump
        $command = "mysqldump --user=$db_user --password=$db_password --host=$host --opt $dbname > $inrtoi";
        exec($command, $output, $result);
        $output = implode(PHP_EOL, $output);
    } else { //localhost
        //mysqldump -u dbUser -p DBName | gzip > OutputFile.sql.gz
        $inrtoi = $backupdir . $dbname . "_archivedAt" . date("Y-m-d") . ".sql";
        $command = "$partition:\\wamp\bin\mysql\mysql5.6.17\bin\mysqldump --user=$db_user --password=$db_password --host=$host --opt $dbname > $inrtoi";
        //$output = passthru($command . " 2>&1");
        $output = passthru($command); //remove " 2>&1" as it writes warning to backup file
    }

    return 1;
}

function move_folder($source, $destination, $sendprogress = 0) {//$sendprogress 0 dont send  , 1 send
    global $currentFile;
    global $allTotal;
    $totalFiles = $allTotal;

    if (!is_dir($source)) {
        return;
    }
    $dir = opendir($source);
    @mkdir($destination);
    while (false !== ( $file = readdir($dir))) {
        if (( $file != '.' ) && ( $file != '..' )) {
            if (is_dir($source . '/' . $file)) {
                $currentFile++;
                move_folder($source . '/' . $file, $destination . '/' . $file);
            } else {
                $currentFile++;
                rename($source . '/' . $file, $destination . '/' . $file);
            }

            if ($sendprogress == 1) {
                sendProgressUnzip($currentFile, $totalFiles, $file);
            }
        }
    }
    closedir($dir);
    // Check if the source directory is empty
    if (count(scandir($source)) == 2) { // 2 because of '.' and '..'
        rmdir($source);
    }
}

function deleteFolder($path, $sendprogress = 0) {//$sendprogress 0 dont send  , 1 send
    global $currentFile;
    global $allTotal;
    $totalFiles = $allTotal;
    $files = scandir($path);
    foreach ($files as $file) {
        if ($file != '.' && $file != '..') {
            $filePath = $path . '/' . $file;
            if (is_dir($filePath)) {
                $currentFile++;
                deleteFolder($filePath);
            } else {
                unlink($filePath);
                $currentFile++;
            }

            if ($sendprogress == 1) {
                sendProgressUnzip($currentFile, $totalFiles, $file);
            }
        }
    }
    rmdir($path);
}

function countFilesAndFolders($dir) {
    global $filesCount;
    global $foldersCount;

    $files = scandir($dir);
    foreach ($files as $file) {
        if ($file != '.' && $file != '..') {
            $filePath = $dir . '/' . $file;
            if (is_file($filePath)) {
                $filesCount++;
            } elseif (is_dir($filePath)) {
                $foldersCount++;
                countFilesAndFolders($filePath);
            }
        }
    }
}

?>