<?php
    require_once('../vendor/autoload.php');

    if(isset($_REQUEST['load'])){
        header('Content-type: text/html');
        die('<html><body><form id="load_form" action="./" method="POST" enctype="multipart/form-data"><input type="file" name="load" onchange="javascript:document.getElementById(\'load_form\').submit();"/></form></body></html>');
    }
    if(isset($_FILES['load'])){
        if($_FILES['load']['error'] == 0 && ($data = file_get_contents($_FILES['load']['tmp_name']))){
            header('Content-type: text/html');
            die('<html><body><script>window.parent.load_template(\'' . addslashes($data) . '\');window.location.href=\'./?load=true\';</script></body></html>');
        }
        header('Content-type: text/html');
        die('<html><body><script>alert("Template could not be loaded!");</script></body></html>');
    }

    if(isset($_POST['save']) || isset($_POST['download'])){
        if(isset($_POST['download'])){
            $data = json_decode($_POST['download'], true);
            if(!is_array($data)){
                header('Content-type: text/html');
                die('<html><body><script>alert("Template could not be saved!");</script></body></html>');
            }
            $code = $data['code'];
            $setup_code = isset($data['setup_code']) ? $data['setup_code'] : null;
            $prepend_code = isset($data['prepend_code']) ? $data['prepend_code'] : null;
            $append_code = isset($data['append_code']) ? $data['append_code'] : null;
            $options = isset($data['options']) ? $data['options'] : array();
            $whitelist = isset($data['whitelist']) ? $data['whitelist'] : null;
            $blacklist = isset($data['blacklist']) ? $data['blacklist'] : null;
            $definitions = isset($data['definitions']) ? $data['definitions'] : null;
            $filename = $template = stripslashes($data['save']);
        } else {
            $code = $_POST['code'];
            $setup_code = isset($_POST['setup_code']) ? $_POST['setup_code'] : null;
            $prepend_code = isset($_POST['prepend_code']) ? $_POST['prepend_code'] : null;
            $append_code = isset($_POST['append_code']) ? $_POST['append_code'] : null;
            $options = isset($_POST['options']) ? $_POST['options'] : array();
            $whitelist = isset($_POST['whitelist']) ? $_POST['whitelist'] : null;
            $blacklist = isset($_POST['blacklist']) ? $_POST['blacklist'] : null;
            $definitions = isset($_POST['definitions']) ? $_POST['definitions'] : null;
            $template = stripslashes(isset($_POST['save']) ? $_POST['save'] : $_POST['download']);
            $filename = isset($_POST['download']) ? $template : trim(preg_replace('/[^a-zA-Z0-9_ ]/', '_', $template), '_');
        }
        if(!$filename){
            header('Content-type: text/html');
            die(json_encode(array(
                'message' => 'The template could not be saved because the requested template name was invalid. Please rename your template and try again.',
                'success' => false
            )));
        }
        $cnt = '001';
        if(isset($_POST['download'])){
            $filename = $filename . '.json';
        } else {
            $cnt = count(glob('templates/*.json')) + 1;
            $filename = str_pad($cnt, 3, '0', STR_PAD_LEFT) . ' - ' . $filename . '.json';
        }
        if(!isset($_POST['download']) && file_exists('templates/' . $filename)){
            header('Content-type: text/html');
            die(json_encode(array(
                'message' => 'The template could not be saved because the another template already exists with the same name. Please rename your template and try again.',
                'success' => false
            )));
        }
        $data = array(
            'code' => $code,
            'setup_code' => $setup_code,
            'prepend_code' => $prepend_code,
            'append_code' => $append_code,
            'options' => null,
            'whitelist' => $whitelist,
            'blacklist' => $blacklist,
            'definitions' => $definitions
        );
        if(count($options)){
            $sandbox = new \PHPSandbox\PHPSandbox;
            foreach($options as $name => $value){
                if(($name == 'error_level' && $value != error_reporting()) || ($name != 'error_level' && $sandbox->getOption($name) != $value)){ //save unique options only
                    $data['options'][$name] = $value;
                }
            }
        }
        if(isset($_POST['download'])){
            header('Content-disposition: attachment; filename="' . $filename . '";');
            header('Content-type: application/json');
            die(json_encode($data));
        } else if(file_put_contents('templates/' . $filename, json_encode($data))){
            header('Content-type: text/html');
            die(json_encode(array(
                'message' => 'The template "' . $template . '" was saved successfully!',
                'name' => $cnt . ' - ' . $template,
                'file' => $filename,
                'success' => true
            )));
        }
        header('Content-type: text/html');
        die(json_encode(array(
            'message' => 'An error occurred that prevented your template from being saved!',
            'success' => false
        )));
    }

    if(isset($_POST['code'])){
        $code = $_POST['code'];
        $setup_code = isset($_POST['setup_code']) ? $_POST['setup_code'] : null;
        $prepend_code = isset($_POST['prepend_code']) ? $_POST['prepend_code'] : null;
        $append_code = isset($_POST['append_code']) ? $_POST['append_code'] : null;
        $options = isset($_POST['options']) ? $_POST['options'] : array();
        $whitelist = isset($_POST['whitelist']) ? $_POST['whitelist'] : null;
        $blacklist = isset($_POST['blacklist']) ? $_POST['blacklist'] : null;
        $definitions = isset($_POST['definitions']) ? $_POST['definitions'] : null;
        $sandbox = \PHPSandbox\PHPSandbox::create()->import(array(
            'setup_code' => $setup_code,
            'prepend_code' => $prepend_code,
            'append_code' => $append_code,
            'options' => $options,
            'whitelist' => $whitelist,
            'blacklist' => $blacklist,
            'definitions' => $definitions
        ));
        $sandbox->setErrorHandler(function($errno, $errmsg, $errfile, $errline){ die('<h2 style="color: red;">Error: ' . $errmsg . ' on line ' . $errline . '</h2>'); });
        $sandbox->setExceptionHandler(function(\Exception $e){ die('<h2 style="color: red;">Exception: ' . $e->getMessage() . ' on line ' . $e->getLine() . '</h2>'); });
        $sandbox->setValidationErrorHandler(function(\PHPSandbox\Error $e){ die('<h2 style="color: red;">Validation Error: ' . $e->getMessage() . '</h2>'); });
        try {
            ob_start();
            if($setup_code){
                @eval($setup_code);
            }
            $result = $sandbox->execute($code);
            if($result !== null){
                echo (ob_get_contents() ? '<hr class="hr"/>' : '') . '<h3>The sandbox returned this value:</h3>';
                var_dump($result);
            }
            echo '<hr class="hr"/>Preparation time: ' . round($sandbox->getPreparedTime()*1000, 2) .
                ' ms, execution time: ' . round($sandbox->getExecutionTime()*1000, 2) .
                ' ms, total time: ' . round($sandbox->getPreparedTime()*1000, 2) . ' ms' .
                '<hr class="hr"/>Generated Code: <code>' . $sandbox->getGeneratedCode() . '</code>';
            $buffer = ob_get_contents();
            ob_end_clean();
            die('<pre>' . $buffer . '</pre>');
        } catch(\PHPSandbox\Error $e){
            die('<h2 style="color: red;">' . $e->getMessage() . '</h2>');
        }
    }

    if(isset($_GET['template'])){
        $template = stripslashes($_GET['template']);
        if(file_exists($template)){
            header('Content-type: text/html');
            readfile($template);
        }
        exit;
    }

    if(isset($_REQUEST['download'])){
        exit;
    }

    $data = json_decode(file_get_contents("templates/001 - Hello World.json"), true);
?>
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html" xmlns="http://www.w3.org/1999/html">
<head>
    <title>PHPSandbox - Toolkit</title>
    <link href="//code.jquery.com/ui/1.11.4/themes/vader/jquery-ui.css" type="text/css" rel="stylesheet"/>
    <script src="//code.jquery.com/jquery-1.12.0.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript" charset="utf-8">
        var JSON;JSON||(JSON={});
        (function(){function k(a){return a<10?"0"+a:a}function o(a){p.lastIndex=0;return p.test(a)?'"'+a.replace(p,function(a){var c=r[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function l(a,j){var c,d,h,m,g=e,f,b=j[a];b&&typeof b==="object"&&typeof b.toJSON==="function"&&(b=b.toJSON(a));typeof i==="function"&&(b=i.call(j,a,b));switch(typeof b){case "string":return o(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b);case "object":if(!b)return"null";
            e+=n;f=[];if(Object.prototype.toString.apply(b)==="[object Array]"){m=b.length;for(c=0;c<m;c+=1)f[c]=l(c,b)||"null";h=f.length===0?"[]":e?"[\n"+e+f.join(",\n"+e)+"\n"+g+"]":"["+f.join(",")+"]";e=g;return h}if(i&&typeof i==="object"){m=i.length;for(c=0;c<m;c+=1)typeof i[c]==="string"&&(d=i[c],(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h))}else for(d in b)Object.prototype.hasOwnProperty.call(b,d)&&(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h);h=f.length===0?"{}":e?"{\n"+e+f.join(",\n"+e)+"\n"+g+"}":"{"+f.join(",")+
                    "}";e=g;return h}}if(typeof Date.prototype.toJSON!=="function")Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+k(this.getUTCMonth()+1)+"-"+k(this.getUTCDate())+"T"+k(this.getUTCHours())+":"+k(this.getUTCMinutes())+":"+k(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()};var q=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
                p=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,e,n,r={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},i;if(typeof JSON.stringify!=="function")JSON.stringify=function(a,j,c){var d;n=e="";if(typeof c==="number")for(d=0;d<c;d+=1)n+=" ";else typeof c==="string"&&(n=c);if((i=j)&&typeof j!=="function"&&(typeof j!=="object"||typeof j.length!=="number"))throw Error("JSON.stringify");return l("",
                {"":a})};if(typeof JSON.parse!=="function")JSON.parse=function(a,e){function c(a,d){var g,f,b=a[d];if(b&&typeof b==="object")for(g in b)Object.prototype.hasOwnProperty.call(b,g)&&(f=c(b,g),f!==void 0?b[g]=f:delete b[g]);return e.call(a,d,b)}var d,a=String(a);q.lastIndex=0;q.test(a)&&(a=a.replace(q,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
                "]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return d=eval("("+a+")"),typeof e==="function"?c({"":d},""):d;throw new SyntaxError("JSON.parse");}})();
    </script>
    <style type="text/css" media="screen">
        #body {
            margin: 0;
            font-family: "Trebuchet MS", sans, sans-serif;
            font-size: 14px;
            background: #ccc;
        }
        #instructions {
            position: absolute;
            top: 0;
            right: 303px;
            left: 0;
            padding: 0 2em;
            height: 60px;
        }
        #toolbar {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            width: 263px;
            padding: 20px;
            border-left: 1px solid gray;
        }
        #output_container {
            position: absolute;
            top: 360px;
            right: 303px;
            left: 0;
            bottom: 0;
            padding: 1em 2em;
        }
        #output {
            height: 70%;
            overflow: auto;
            padding: 1em;
            font-size: 12px;
        }
        #editor {
            position: absolute;
            top: 60px;
            right: 303px;
            left: 0;
            height: 300px;
            border: 1px solid gray;
            border-left: 0;
        }
        .hr {
            border: 1px solid transparent;
            border-top: 1px dashed gray;
        }
        #configuration_container {
            height: 360px;
        }
        #configuration {
            font-size: 11px;
        }
        #templates {
            width: 100%;
            font-size: 12px;
        }
        #toolbar label {
            font-weight: bold;
            margin: .5em;
        }
        input.whitelist, input.blacklist, input.func, input.var, input.superglobal, input.const, input.magic_const, input.namespace, input.alias, input.class, input.interface, input.trait {
            width: 100%;
            text-align: left;
        }
        #mode_container {
            float: right;
            margin-top: 1em;
        }
        #func_editor_dialog, #var_editor_dialog, #superglobal_editor_dialog, #const_editor_dialog,
        #magic_const_editor_dialog, #namespace_editor_dialog, #alias_editor_dialog, #class_editor_dialog,
        #interface_editor_dialog, #trait_editor_dialog, #help_dialog {
            display: none;
            font-size: 12px;
        }
        #func_editor {
            border: 1px solid gray;
        }
        #func_editor_name, #func_editor_args {
            font-family: "Courier New", serif;
            font-size: 10px;
        }
        .ui-dialog-titlebar {
            font-size: 12px;
        }
        .ui-dialog-content {
            padding-left: 0.7em !important;
        }
        .ui-dialog-buttonset {
            width: 100%;
            font-size: 12px;
            font-weight: bold;
        }
        .ui-dialog-buttonset .ui-button:last-child {
            float: left;
            margin-left: 1em;
        }
        .ui-dialog-buttonset .ui-button:first-child {
            float: right;
        }
        #download, #download_form, #load {
            display: none;
        }
    </style>
    <script type="text/javascript" >
        var code = <?php echo json_encode(isset($data['code']) ? $data['code'] : ''); ?>,
            setup_code = <?php echo json_encode(isset($data['setup_code']) ? $data['setup_code'] : ''); ?>,
            prepend_code = <?php echo json_encode(isset($data['prepend_code']) ? $data['prepend_code'] : ''); ?>,
            append_code = <?php echo json_encode(isset($data['append_code']) ? $data['append_code'] : ''); ?>,
            current_mode = 'code';
    </script>
</head>
<body id="body">
<div id="instructions">
    <span id="mode_container">
        <label for="mode"><strong>Editor Mode:</strong></label>
        <select id="mode">
            <option value="code">Sandboxed Code</option>
            <optgroup label="Trusted Code">
                <option value="setup_code">Setup Code (runs before code and outside sandbox)</option>
                <option value="prepend_code">Prepended Code (runs before code inside sandbox)</option>
                <option value="append_code">Appended Code (runs after code inside sandbox)</option>
            </optgroup>
        </select>
    </span>
    <h2>Code Editor</h2>
</div>
<div id="toolbar">
    <a href="https://github.com/fieryprophet/php-sandbox" target="_blank"><img src="data:image/png;base64, " alt="PHPSandbox" style="border: 0;"></a>
    <p align="center" style="margin-top: 2px;">
        <strong>
            <a href="../docs/" target="_blank">API Documentation</a>
        </strong>
        &nbsp;&nbsp;&mdash;&nbsp;&nbsp;
        <strong>
            <a href="javascript:;" class="help">Help</a>
        </strong>
    </p>
    <div align="center" style="font-size: 8px; font-weight: bold;">&copy; Copyright 2013 - <?php echo date("Y"); ?> Corveda, LLC. - Some Rights Reserved.<br/>See <a href="../LICENSE" target="_blank">LICENSE</a> for details.</div>
    <hr class="hr"/>
    <h3 style="margin: 0;">Choose Template:</h3>
    <br/>
    <select id="templates">
        <option disabled="disabled">Select a template. . .</option>
    <?php
        foreach(glob("templates/*.json") as $index => $template){
            echo '<option value="' . htmlentities($template) . '">' . ($index + 1) . ' - ' . htmlentities(substr($template, 16, strlen($template) - 21)) . '</option>';
        }
    ?>
    </select>
    <br/>
    <br/>
    <input type="button" class="load" value="Import A Template" style="width: 100%;"/>
    <hr class="hr"/>
    <input type="button" value="Save As New Template" id="save" style="width: 100%;"/>
    <div align="center" style="margin-top: 3px; margin-bottom: -2px;">
        <input type="checkbox" id="download_check" value="yes"/>
        <strong style="line-height: 19px; vertical-align: top;">Download template?</strong>
    </div>
    <hr class="hr"/>
    <h3>Sandbox Configuration:</h3>
    <div id="configuration_container">
        <div id="configuration">
            <h3>Options</h3>
            <div id="options">
                <?php
                $sandbox = new \PHPSandbox\PHPSandbox;
                foreach($sandbox as $name => $flag){
                    if(is_bool($flag)){
                        $lastname = strstr($name, '_', true);
                        $name = htmlentities($name);
                        echo '<input type="checkbox" value="true" name="' . $name . '" id="' . $name . '"' . ($flag ? ' checked="checked"' : '') . '/>';
                        echo '<label for="' . $name . '">' . htmlentities(ucwords(str_replace(array('_', 'funcs', 'vars'), array(' ', 'functions', 'variables'), $name))) . '</label><br/>';
                    }
                }
                ?>
            </div>
            <h3>Whitelists</h3>
            <div>
                <strong>Add To: </strong>
                <select id="whitelist_select" style="margin-bottom: 3px;">
                    <option value="func">Functions</option>
                    <option value="var">Variables</option>
                    <option value="global">Globals</option>
                    <option value="superglobal">Superglobals</option>
                    <option value="const">Constants</option>
                    <option value="magic_const">Magic Constants</option>
                    <option value="namespace">Namespaces</option>
                    <option value="alias">Aliases (aka Use)</option>
                    <option value="class">Classes</option>
                    <option value="interface">Interfaces</option>
                    <option value="trait">Traits</option>
                    <option value="keyword">Keywords</option>
                    <option value="operator">Operators</option>
                    <option value="primitive">Primitives</option>
                    <option value="type">Types</option>
                </select>
                <br/>
                <input type="text" id="whitelist" value="" title="Invalid name for whitelisted item!"/>
                <input type="button" value="+" id="whitelist_add"/>
                <br/>
                <strong style="font-size: 9px;">NOTE: Whitelists override blacklists.</strong>
                <hr class="hr"/>
                <div id="whitelist_func" style="display: none;">
                    <strong>Functions:</strong>
                </div>
                <div id="whitelist_var" style="display: none;">
                    <strong>Variables:</strong>
                </div>
                <div id="whitelist_global" style="display: none;">
                    <strong>Globals:</strong>
                </div>
                <div id="whitelist_superglobal" style="display: none;">
                    <strong>Superglobals:</strong>
                </div>
                <div id="whitelist_const" style="display: none;">
                    <strong>Constants:</strong>
                </div>
                <div id="whitelist_magic_const" style="display: none;">
                    <strong>Magic Constants:</strong>
                </div>
                <div id="whitelist_namespace" style="display: none;">
                    <strong>Namespaces:</strong>
                </div>
                <div id="whitelist_alias" style="display: none;">
                    <strong>Aliases (aka Use):</strong>
                </div>
                <div id="whitelist_class" style="display: none;">
                    <strong>Classes:</strong>
                </div>
                <div id="whitelist_interface" style="display: none;">
                    <strong>Interfaces:</strong>
                </div>
                <div id="whitelist_trait" style="display: none;">
                    <strong>Traits:</strong>
                </div>
                <div id="whitelist_keyword" style="display: none;">
                    <strong>Keywords:</strong>
                </div>
                <div id="whitelist_operator" style="display: none;">
                    <strong>Operators:</strong>
                </div>
                <div id="whitelist_primitive" style="display: none;">
                    <strong>Primitives:</strong>
                </div>
                <div id="whitelist_type" style="display: none;">
                    <strong>Types:</strong>
                </div>
            </div>
            <h3>Blacklists</h3>
            <div>
                <strong>Add To: </strong>
                <select id="blacklist_select" style="margin-bottom: 3px;">
                    <option value="func">Functions</option>
                    <option value="var">Variables</option>
                    <option value="global">Globals</option>
                    <option value="superglobal">Superglobals</option>
                    <option value="const">Constants</option>
                    <option value="magic_const">Magic Constants</option>
                    <option value="namespace">Namespaces</option>
                    <option value="alias">Aliases (aka Use)</option>
                    <option value="class">Classes</option>
                    <option value="interface">Interfaces</option>
                    <option value="trait">Traits</option>
                    <option value="keyword">Keywords</option>
                    <option value="operator">Operators</option>
                    <option value="primitive">Primitives</option>
                    <option value="type">Types</option>
                </select>
                <br/>
                <input type="text" id="blacklist" value="" title="Invalid name for blacklisted item!"/>
                <input type="button" value="+" id="blacklist_add"/>
                <br/>
                <strong style="font-size: 9px;">NOTE: Whitelists override blacklists.</strong>
                <hr class="hr"/>
                <div id="blacklist_func" style="display: none;">
                    <strong>Functions:</strong>
                </div>
                <div id="blacklist_var" style="display: none;">
                    <strong>Variables:</strong>
                </div>
                <div id="blacklist_global" style="display: none;">
                    <strong>Globals:</strong>
                </div>
                <div id="blacklist_superglobal" style="display: none;">
                    <strong>Superglobals:</strong>
                </div>
                <div id="blacklist_const" style="display: none;">
                    <strong>Constants:</strong>
                </div>
                <div id="blacklist_magic_const" style="display: none;">
                    <strong>Magic Constants:</strong>
                </div>
                <div id="blacklist_namespace" style="display: none;">
                    <strong>Namespaces:</strong>
                </div>
                <div id="blacklist_alias" style="display: none;">
                    <strong>Aliases (aka Use):</strong>
                </div>
                <div id="blacklist_class" style="display: none;">
                    <strong>Classes:</strong>
                </div>
                <div id="blacklist_interface" style="display: none;">
                    <strong>Interfaces:</strong>
                </div>
                <div id="blacklist_trait" style="display: none;">
                    <strong>Traits:</strong>
                </div>
                <div id="blacklist_keyword" style="display: none;">
                    <strong>Keywords:</strong>
                </div>
                <div id="blacklist_operator" style="display: none;">
                    <strong>Operators:</strong>
                </div>
                <div id="blacklist_primitive" style="display: none;">
                    <strong>Primitives:</strong>
                </div>
                <div id="blacklist_type" style="display: none;">
                    <strong>Types:</strong>
                </div>
            </div>
            <h3>Definitions</h3>
            <div>
                <select id="define_select" style="margin-bottom: 3px;">
                    <option value="func">Function</option>
                    <option value="var">Variable</option>
                    <option value="superglobal">Superglobal</option>
                    <option value="const">Constant</option>
                    <option value="magic_const">Magic Constant</option>
                    <option value="namespace">Namespace</option>
                    <option value="alias">Alias (aka Use)</option>
                    <option value="class">Class</option>
                    <option value="interface">Interface</option>
                    <option value="trait">Trait</option>
                </select>
                <input type="button" value="Define" id="define_add"/>
                <br/>
                <strong style="font-size: 9px;">NOTE: Definitions override both whitelists and blacklists, and are inherently trusted.</strong>
                <hr class="hr"/>
                <div id="define_func" style="display: none;">
                    <strong>Functions:</strong>
                </div>
                <div id="define_var" style="display: none;">
                    <strong>Variables:</strong>
                </div>
                <div id="define_superglobal" style="display: none;">
                    <strong>Superglobals:</strong>
                </div>
                <div id="define_const" style="display: none;">
                    <strong>Constants:</strong>
                </div>
                <div id="define_magic_const" style="display: none;">
                    <strong>Magic Constants:</strong>
                </div>
                <div id="define_namespace" style="display: none;">
                    <strong>Namespaces:</strong>
                </div>
                <div id="define_alias" style="display: none;">
                    <strong>Aliases (aka Use):</strong>
                </div>
                <div id="define_class" style="display: none;">
                    <strong>Classes:</strong>
                </div>
                <div id="define_interface" style="display: none;">
                    <strong>Interfaces:</strong>
                </div>
                <div id="define_trait" style="display: none;">
                    <strong>Traits:</strong>
                </div>
            </div>
        </div>
    </div>
    <br/>
    <label for="error_level">Error Level:</label>
    <select id="error_level">
        <?php
            foreach(array('E_ALL' => E_ALL, 'E_ERROR' => E_ERROR, 'E_WARNING' => E_WARNING, 'E_NONE' => 0) as $name => $level){
                echo '<option value="' . $level . '"' . (error_reporting() == $level ? ' selected="selected"' : '') . '>' . ucfirst(strtolower(substr($name, 2))) . '</option>';
            }
        ?>
    </select>
    <br/>
    <br/>
    <input type="button" value="Run Code In Sandbox" id="run" style="width: 100%;"/>
    <br/>
</div>
<div id="output_container">
    <h2>Output</h2>
    <div id="output" class="ui-widget ui-widget-content ui-corner-all"><pre>Hello World!</pre></div>
</div>
<div id="editor"><?php
    echo isset($data['code']) ? $data['code'] : '';
?></div>
<div id="func_editor_dialog" title="Defined Function Editor">
    <span style="float: right;">
        <label>
            <strong>Pass PHPSandbox instance to this function?</strong>
        </label>
        <input type="checkbox" id="func_editor_pass" value="1"/>
    </span>
    <strong>Function Name: </strong>
    <br/>
    <input type="text" id="func_editor_name" style="width: 100%;" value=""/>
    <br/>
    <br/>
    <strong>Enter function arguments below in <em>$argument = value</em> format, e.g. <em>$foo = 'Hello', $bar = 'World'</em></strong>
    <br/>
    <input type="text" id="func_editor_args" style="width: 100%;" value=""/>
    <pre id="func_editor_preview">function (){</pre>
    <div id="func_editor" style="width: 780px; height: 300px;"></div>
    <pre style="margin-top: 324px;">}</pre>
</div>
<div id="var_editor_dialog" title="Defined Variable Editor">
    <strong>Variable Name: </strong>
    <br/>
    <input type="text" id="var_editor_name" style="width: 100%;" value=""/>
    <br/>
    <br/>
    <strong>Variable Type: </strong>
    <br/>
    <select id="var_editor_scalar">
        <option value="string">String</option>
        <option value="bool">Boolean</option>
        <option value="int">Integer</option>
        <option value="float">Float</option>
        <option value="null">Null</option>
    </select>
    <br/>
    <br/>
    <strong>Variable Value: </strong>
    <br/>
    <input type="text" id="var_editor_value" style="width: 100%;" value=""/>
    <pre id="var_editor_preview"></pre>
</div>
<div id="superglobal_editor_dialog" title="Defined Superglobal Editor">
    <strong>Superglobal: </strong>
    <br/>
    <select id="superglobal_editor_name">
        <?php
        foreach(\PHPSandbox\PHPSandbox::$superglobals as $superglobal){
            ?><option value="<?=ltrim($superglobal, '_');?>">$<?=$superglobal?></option><?php
        }
        ?>
    </select>
    <br/>
    <br/>
    <strong>Key: </strong>
    <br/>
    <br/>
    <input type="text" id="superglobal_editor_key" style="width: 100%;" value=""/>
    <br/>
    <br/>
    <strong>Superglobal Type: </strong>
    <br/>
    <select id="superglobal_editor_scalar">
        <option value="string">String</option>
        <option value="bool">Boolean</option>
        <option value="int">Integer</option>
        <option value="float">Float</option>
        <option value="null">Null</option>
    </select>
    <br/>
    <br/>
    <strong>Superglobal Value: </strong>
    <br/>
    <input type="text" id="superglobal_editor_value" style="width: 100%;" value=""/>
    <pre id="superglobal_editor_preview"></pre>
</div>
<div id="const_editor_dialog" title="Defined Constant Editor">
    <strong>Constant Name: </strong>
    <br/>
    <input type="text" id="const_editor_name" style="width: 100%;" value=""/>
    <br/>
    <br/>
    <strong>Constant Type: </strong>
    <br/>
    <select id="const_editor_scalar">
        <option value="string">String</option>
        <option value="bool">Boolean</option>
        <option value="int">Integer</option>
        <option value="float">Float</option>
        <option value="null">Null</option>
    </select>
    <br/>
    <br/>
    <strong>Constant Value: </strong>
    <br/>
    <input type="text" id="const_editor_value" style="width: 100%;" value=""/>
    <pre id="const_editor_preview"></pre>
</div>
<div id="magic_const_editor_dialog" title="Defined Magic Constant Editor">
    <strong>Magic Constant: </strong>
    <br/>
    <select id="magic_const_editor_name">
        <?php
            foreach(\PHPSandbox\PHPSandbox::$magic_constants as $magic_constant){
                ?><option value="<?=$magic_constant?>"><?=$magic_constant?></option><?php
            }
        ?>
    </select>
    <br/>
    <br/>
    <strong>Magic Constant Type: </strong>
    <br/>
    <select id="magic_const_editor_scalar">
        <option value="string">String</option>
        <option value="bool">Boolean</option>
        <option value="int">Integer</option>
        <option value="float">Float</option>
        <option value="null">Null</option>
    </select>
    <br/>
    <br/>
    <strong>Magic Constant Value: </strong>
    <br/>
    <input type="text" id="magic_const_editor_value" style="width: 100%;" value=""/>
    <pre id="magic_const_editor_preview"></pre>
</div>
<div id="namespace_editor_dialog" title="Defined Namespace Editor">
    <strong>Namespace: </strong>
    <br/>
    <input type="text" id="namespace_editor_name" style="width: 100%;" value=""/>
    <pre id="namespace_editor_preview"></pre>
</div>
<div id="alias_editor_dialog" title="Defined Alias (aka Use) Editor">
    <strong>Use: </strong>
    <br/>
    <input type="text" id="alias_editor_name" style="width: 100%;" value=""/>
    <br/>
    <br/>
    <strong>Alias (leave blank for none): </strong>
    <br/>
    <input type="text" id="alias_editor_value" style="width: 100%;" value=""/>
    <pre id="alias_editor_preview"></pre>
</div>
<div id="class_editor_dialog" title="Defined Class Editor">
    <strong>Redefine Class: </strong>
    <br/>
    <input type="text" id="class_editor_name" style="width: 100%;" value=""/>
    <br/>
    <br/>
    <strong>To: </strong>
    <br/>
    <input type="text" id="class_editor_value" style="width: 100%;" value=""/>
    <pre id="class_editor_preview"></pre>
</div>
<div id="interface_editor_dialog" title="Defined Interface Editor">
    <strong>Redefine Interface: </strong>
    <br/>
    <input type="text" id="interface_editor_name" style="width: 100%;" value=""/>
    <br/>
    <br/>
    <strong>To: </strong>
    <br/>
    <input type="text" id="interface_editor_value" style="width: 100%;" value=""/>
    <pre id="interface_editor_preview"></pre>
</div>
<div id="trait_editor_dialog" title="Defined Trait Editor">
    <strong>Redefine Trait: </strong>
    <br/>
    <input type="text" id="trait_editor_name" style="width: 100%;" value=""/>
    <br/>
    <br/>
    <strong>To: </strong>
    <br/>
    <input type="text" id="trait_editor_value" style="width: 100%;" value=""/>
    <pre id="trait_editor_preview"></pre>
</div>
<div id="help_dialog" title="PHPSandbox Toolkit Help">
    <iframe src="../MANUAL.html" frameborder="0" height="600" width="100%"></iframe>
</div>
<iframe src="./?load=true" id="load" name="load"></iframe>
<iframe src="./?download=true" id="download" name="download"></iframe>
<form action="./" id="download_form" target="download" method="post">
    <input type="hidden" id="download_data" name="download" value=""/>
</form>
<script src="//cdnjs.cloudflare.com/ajax/libs/ace/1.2.3/ace.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
    var editor = ace.edit("editor");
    editor.setTheme("ace/theme/github");
    editor.getSession().setMode("ace/mode/php");
    function invalid(name, type){
        if(type == 'var' || type == 'global' || type == 'const'){
            return ((/[^a-z0-9_]+/i.test(name)) || (/[^a-z_]+/i.test(name.substring(0, 1))));
        } else if(type == 'func' || type == 'namespace' || type == 'alias' || type == 'class' || type == 'interface' || type == 'trait' || type == 'type'){
            return ((/[^a-z0-9_\\]+/i.test(name)) || (/[^a-z_\\]+/i.test(name.substring(0, 1))));
        } else if(type == 'keyword' || type == 'primitive'){
            return (/[^a-z]+/.test(name));
        } else if(type == 'superglobal' || type == 'magic_const'){
            return ((/[^A-Z0-9_]+/.test(name)) || (/[^A-Z_]+/.test(name.substring(0, 1))));
        }
        return false;
    }
    function name_button(name, type, key){
        switch(type){
            case 'func':
                name += '();';
                break;
            case 'var':
                name = '$' + name;
                break;
            case 'global':
                name = 'global $' + name + ';';
                break;
            case 'superglobal':
                name = name.toUpperCase().replace('_', '');
                name = (name == 'GLOBALS' ? '$' + name : '$_' + name) + (key ? "['" + key + "']" : "");
                break;
            case 'const':
                name = name.toUpperCase();
                break;
            case 'magic_const':
                name = '__' + name.toUpperCase().replace('_', '') + '__';
                break;
            case 'alias':
                name = key ? (name + ' as ' + key) : name;
                break;
            case 'namespace':
            case 'type':
                break;
            case 'class':
            case 'interface':
            case 'trait':
                name = key ? (name + ' => ' + key) : name;
                break;
            case 'keyword':
            case 'primitive':
                name = name.toLowerCase();
                break;
        }
        return name;
    }
    function list_keyup(el, select){
        if(invalid(el.val(), $(select).val())){
            el.tooltip("enable");
            el.tooltip("open");
        } else {
            el.tooltip("close");
            el.tooltip("disable");
        }
    }
    function make_button(button_name, button_class, type, name){
        return $("<input/>").attr({"value": button_name, "type": "button", "class": button_class}).data({"type": type, "name": name});
    }
    function sync_code(from_vars){
        if(from_vars){
            switch(current_mode){
                case 'code':
                    editor.setValue(code);
                    break;
                case 'setup_code':
                    editor.setValue(setup_code);
                    break;
                case 'prepend_code':
                    editor.setValue(prepend_code);
                    break;
                case 'append_code':
                    editor.setValue(append_code);
                    break;
            }
            editor.clearSelection();
        } else {
            switch(current_mode){
                case 'code':
                    code = editor.getValue();
                    break;
                case 'setup_code':
                    setup_code = editor.getValue();
                    break;
                case 'prepend_code':
                    prepend_code = editor.getValue();
                    break;
                case 'append_code':
                    append_code = editor.getValue();
                    break;
            }
        }
    }
    function load_template(response){
        if(typeof response == "string"){
            response = JSON.parse(response);
        }
        if(!response || typeof response != "object"){
            alert("Could not load template!");
            return;
        }
        code = response.code ? response.code : "";
        setup_code = response.setup_code ? response.setup_code : "";
        prepend_code = response.prepend_code ? response.prepend_code : "";
        append_code = response.append_code ? response.append_code : "";
        sync_code(true);
        var x, type, name, list, button_name, i, button, data;
        if(response.options && response.options.length){
            for(x in response.options){
                if(x == 'error_level'){
                    $('#error_level').val(response.options[x])
                } else {
                    $("#" + x).prop('checked', response.options[x] ? true : false);
                }
            }
        }
        $('input.whitelist, input.blacklist, input.func, input.var, input.superglobal, input.const, input.magic_const, input.namespace, input.alias, input.class, input.interface, input.trait').each(function(){
            var el = $(this);
            el.parent().hide();
            el.remove();
        });
        if(response.whitelist){
            for(type in response.whitelist){
                list = $("#whitelist_" + type);
                if(response.whitelist[type]){
                    for(i = 0; i<response.whitelist[type].length; i++){
                        name = response.whitelist[type][i];
                        button_name = name_button(name, type);
                        list.append(make_button(button_name, "whitelist", type, name)).show();
                    }
                }
            }
        }
        if(response.blacklist){
            for(type in response.blacklist){
                list = $("#blacklist_" + type);
                if(response.blacklist[type]){
                    for(i = 0; i<response.blacklist[type].length; i++){
                        name = response.blacklist[type][i];
                        button_name = name_button(name, type);
                        list.append(make_button(button_name, "blacklist", type, name)).show();
                    }
                }
            }
        }
        if(response.definitions){
            for(type in response.definitions){
                list = $("#define_" + type);
                if(response.definitions[type]){
                    for(name in response.definitions[type]){
                        data = response.definitions[type][name];
                        switch(type){
                            case 'func':
                                button_name = name_button(name, type);
                                button = make_button(button_name, type, type, name);
                                button.data({"args": data.args, "code": data.code, "pass": data.pass, "fullcode": data.fullcode});
                                break;
                            case 'var':
                            case 'const':
                            case 'magic_const':
                                button_name = name_button(name, type);
                                button = make_button(button_name, type, type, name);
                                button.data({"scalar": data.scalar, "value": data.value});
                                break;
                            case 'superglobal':
                                button_name = name_button(name, type, data.key);
                                button = make_button(button_name, type, type, name);
                                button.data({"key": data.key, "scalar": data.scalar, "value": data.value});
                                break;
                            case 'namespace':
                                button_name = name_button(name, type);
                                button = make_button(button_name, type, type, name);
                                break;
                            case 'alias':
                            case 'class':
                            case 'interface':
                            case 'trait':
                                button_name = name_button(name, type, data);
                                button = make_button(button_name, type, type, name);
                                button.data({"value": data});
                                break;
                        }
                        list.append(button).show();
                    }
                }
            }
        }
    }
    $(function(){
        var wl = $("#whitelist").tooltip();
        wl.tooltip("disable");
        wl.on('keyup', function(){
            list_keyup($(this), "#whitelist_select");
        });
        var bl = $("#blacklist").tooltip();
        bl.tooltip("disable");
        bl.on('keyup', function(){
            list_keyup($(this), "#blacklist_select");
        });
        $("#configuration").accordion({heightStyle: "fill"});
        $("#templates").on('change', function(){
            var template = $(this).val();
            $.getJSON("./", {"template": template}, function(response){
                load_template(response);
            });
        });
        $("#run, #save").button().on('click', function(){
            sync_code();
            var options = {}, list = function(){
                return {
                    "func": {},
                    "var": {},
                    "global": {},
                    "superglobal": {},
                    "const": {},
                    "magic_const": {},
                    "namespace": {},
                    "alias": {},
                    "class": {},
                    "interface": {},
                    "trait": {},
                    "keyword": {},
                    "operator": {},
                    "primitive": {},
                    "type": {}
                };
            }, whitelist = list(), blacklist = list(), definitions = {
                "func": {},
                "var": {},
                "superglobal": {},
                "const": {},
                "magic_const": {},
                "namespace": {},
                "alias": {},
                "class": {},
                "interface": {},
                "trait": {}
            };
            $("#options").find("input").each(function(){
               var name = $(this).attr('name');
               options[name] = $(this).is(":checked") ? 1 : 0;
            });
            var x, i;
            for(x in whitelist){
                i = 0;
                $("#whitelist_" + x).find('input').each(function(){
                   var el = $(this), type = el.data('type');
                   whitelist[type][i] = el.data('name');
                   i++;
                });
            }
            for(x in blacklist){
                i = 0;
                $("#blacklist_" + x).find('input').each(function(){
                    var el = $(this), type = el.data('type');
                    blacklist[type][i] = el.data('name');
                    i++;
                });
            }
            for(x in definitions){
                i = 0;
                $("#define_" + x).find('input').each(function(){
                    var el = $(this), type = el.data('type');
                    switch(type){
                        case 'func':
                            definitions[type][el.data('name')] = {
                                "args" : el.data('args'),
                                "code": el.data('code'),
                                "pass": el.data('pass') ? 1 : 0,
                                "fullcode": el.data('fullcode')
                            };
                            break;
                        case 'var':
                        case 'const':
                        case 'magic_const':
                            definitions[type][el.data('name')] = {
                                "scalar": el.data('scalar'),
                                "value": el.data('value')
                            };
                            break;
                        case 'superglobal':
                            definitions[type][el.data('name')] = {
                                "key": el.data('key'),
                                "scalar": el.data('scalar'),
                                "value": el.data('value')
                            };
                            break;
                        case 'namespace':
                            definitions[type][el.data('name')] = el.data('name');
                            break;
                        case 'alias':
                        case 'class':
                        case 'interface':
                        case 'trait':
                            definitions[type][el.data('name')] = el.data('value');
                            break;
                    }
                    i++;
                });
            }
            options.error_level = $("#error_level").val();
            if($(this).attr('id') == 'save'){
                var download = $("#download_check").is(":checked");
                var name = prompt("What do you want to name this new template?" + (download ? "" : " It will be saved in toolkit/templates/"), "New Template");
                if(!name){
                    alert("Can't save a template without a name!");
                    return;
                }
                if(download){
                    var data = JSON.stringify({"code": code, "setup_code": setup_code, "prepend_code": prepend_code, "append_code": append_code, "options": options, "whitelist" : whitelist, "blacklist": blacklist, "definitions": definitions, "save": name});
                    $("#download_data").val(data);
                    $("#download_form").submit();
                    return;
                }
                $.post("./", {"code": code, "setup_code": setup_code, "prepend_code": prepend_code, "append_code": append_code, "options": options, "whitelist" : whitelist, "blacklist": blacklist, "definitions": definitions, "save": name}, function(response){
                    alert(response.message);
                    if(response.success){
                        $("#templates").append('<option value="templates/' + response.file + '">' + response.name + '</option>').val('templates/' + response.file);
                    }
                }, 'json');
            } else {
                $.post("./", {"code": code, "setup_code": setup_code, "prepend_code": prepend_code, "append_code": append_code, "options": options, "whitelist" : whitelist, "blacklist": blacklist, "definitions": definitions}, function(response){
                    $("#output").html(response);
                })
            }
        });
        $("#whitelist_add").on("click", function(){
            var el = $("#whitelist");
            var name = el.val();
            var type = $("#whitelist_select").val();
            var list = $("#whitelist_" + type);
            if(!name){
               return;
            }
            if(invalid(name, type)){
                el.tooltip("enable");
                el.tooltip("open");
                return;
            }
            var button_name = name_button(name, type);
            if(list.find('input[value="' + button_name + '"]').length){
                return;
            }
            list.append(make_button(button_name, "whitelist", type, name)).show();
            el.val('');
        });
        $("#blacklist_add").on("click", function(){
            var el = $("#blacklist");
            var name = el.val();
            var type = $("#blacklist_select").val();
            var list = $("#blacklist_" + type);
            if(!name){
                return;
            }
            if(invalid(name, type)){
                el.tooltip("enable");
                el.tooltip("open");
                return;
            }
            var button_name = name_button(name, type);
            if(list.find('input[value="' + button_name + '"]').length){
                return;
            }
            list.append(make_button(button_name, "blacklist", type, name)).show();
            el.val('');
        });
        $(document).on('click', 'input.whitelist, input.blacklist', function(){
            var el = $(this);
            if(el.parent().children('input').length < 2){
                el.parent().hide();
            }
            el.remove();
        });
        $("#mode").on('change', function(){
            sync_code();
            switch($(this).val()){
                case 'code':
                    editor.setValue(code);
                    current_mode = 'code';
                    break;
                case 'setup_code':
                    editor.setValue(setup_code);
                    current_mode = 'setup_code';
                    break;
                case 'prepend_code':
                    editor.setValue(prepend_code);
                    current_mode = 'prepend_code';
                    break;
                case 'append_code':
                    editor.setValue(append_code);
                    current_mode = 'append_code';
                    break;
            }
            editor.clearSelection();
        });
    });
    $("#define_add").on('click', function(){
        launch_editor($("#define_select").val());
    });
    $(document).on('click', "input.func, input.var, input.superglobal, input.const, input.magic_const, input.namespace, input.alias, input.class, input.interface, input.trait", function(){
        launch_editor($(this).attr('class'), $(this));
    });
    $("#func_editor_name, #func_editor_args").on('keyup', function(){
        if($(this).attr('id') == 'func_editor_name'){
            $(this).val($(this).val().replace(/[^a-z0-9_\\]+/i, '_'));
        }
        var name = $("#func_editor_name").val(), args = $("#func_editor_args").val();
        $("#func_editor_preview").html('function ' + name + '(' + args + '){');
    });
    function var_preview(name, scalar, value){
        switch(scalar){
            case 'int':
                value = value.replace(/[^0-9]+/i, '') || 0;
                break;
            case 'float':
                value = value.replace(/[^0-9.]+/i, '') || 0;
                break;
            case 'bool':
                value = (value.toLowerCase() == 'true' || parseInt(value)) ? 'true' : 'false';
                break;
            case 'null':
                value = 'null';
                break;
        }
        $("#var_editor_value").val(value);
        $("#var_editor_preview").html(name ? ('$' + name + ' = ' + (scalar == 'string' ? "'" + value + "'" : value) + ';') : '');
    }
    $("#var_editor_name").on('keyup', function(){
        $(this).val($(this).val().replace(/[^a-z0-9_]+/i, '_'));
        var_preview($("#var_editor_name").val(), $("#var_editor_scalar").val(), $("#var_editor_value").val());
    });
    $("#var_editor_scalar").on('change', function(){
        var scalar = $("#var_editor_scalar").val(), v = $("#var_editor_value"), value = v.val();
        if(scalar == 'bool'){
            v.replaceWith('<select id="var_editor_value"><option value="true">true</option><option value="false">false</option></select>');
        } else if(scalar == 'null'){
            v.replaceWith('<input type="text" id="var_editor_value" style="width: 100%;" value="" disabled="disabled"/>');
        } else {
            v.replaceWith('<input type="text" id="var_editor_value" style="width: 100%;" value=""/>');
        }
        var_preview($("#var_editor_name").val(), scalar, (scalar == 'string' ? '' : value));
    });
    $(document).on('keyup change', "#var_editor_value", function(){
        var_preview($("#var_editor_name").val(), $("#var_editor_scalar").val(), $("#var_editor_value").val());
    });
    function superglobal_preview(name, key, scalar, value){
        switch(scalar){
            case 'int':
                value = value.replace(/[^0-9]+/i, '') || 0;
                break;
            case 'float':
                value = value.replace(/[^0-9.]+/i, '') || 0;
                break;
            case 'bool':
                value = (value.toLowerCase() == 'true' || parseInt(value)) ? 'true' : 'false';
                break;
            case 'null':
                value = 'null';
                break;
        }
        $("#superglobal_editor_value").val(value);
        $("#superglobal_editor_preview").html(name ? ('$' + name + "['" + key + "'] = " + (scalar == 'string' ? "'" + value + "'" : value) + ';') : '');
    }
    $(document).on('keyup change', "#superglobal_editor_name, #superglobal_editor_key, #superglobal_editor_value", function(){
       superglobal_preview($("#superglobal_editor_name").val(), $("#superglobal_editor_key").val(), $("#superglobal_editor_scalar").val(), $("#superglobal_editor_value").val());
    });
    $("#superglobal_editor_scalar").on('change', function(){
        var scalar = $("#superglobal_editor_scalar").val(), v = $("#superglobal_editor_value"), value = v.val();
        if(scalar == 'bool'){
            v.replaceWith('<select id="superglobal_editor_value"><option value="true">true</option><option value="false">false</option></select>');
        } else if(scalar == 'null'){
            v.replaceWith('<input type="text" id="superglobal_editor_value" style="width: 100%;" value="" disabled="disabled"/>');
        } else {
            v.replaceWith('<input type="text" id="superglobal_editor_value" style="width: 100%;" value=""/>');
        }
        superglobal_preview($("#superglobal_editor_name").val(), $("#superglobal_editor_key").val(), scalar, (scalar == 'string' ? '' : value));
    });
    function const_preview(name, scalar, value){
        switch(scalar){
            case 'int':
                value = value.replace(/[^0-9]+/i, '') || 0;
                break;
            case 'float':
                value = value.replace(/[^0-9.]+/i, '') || 0;
                break;
            case 'bool':
                value = (value.toLowerCase() == 'true' || parseInt(value)) ? 'true' : 'false';
                break;
            case 'null':
                value = 'null';
                break;
        }
        $("#const_editor_value").val(value);
        $("#const_editor_preview").html(name ? (name.toUpperCase() + ' = ' + (scalar == 'string' ? "'" + value + "'" : value) + ';') : '');
    }
    $("#const_editor_name").on('keyup', function(){
        $(this).val($(this).val().replace(/[^a-z0-9_]+/i, '_').toUpperCase());
        const_preview($("#const_editor_name").val(), $("#const_editor_scalar").val(), $("#const_editor_value").val());
    });
    $("#const_editor_scalar").on('change', function(){
        var scalar = $("#const_editor_scalar").val(), v = $("#const_editor_value"), value = v.val();
        if(scalar == 'bool'){
            v.replaceWith('<select id="const_editor_value"><option value="true">true</option><option value="false">false</option></select>');
        } else if(scalar == 'null'){
            v.replaceWith('<input type="text" id="const_editor_value" style="width: 100%;" value="" disabled="disabled"/>');
        } else {
            v.replaceWith('<input type="text" id="const_editor_value" style="width: 100%;" value=""/>');
        }
        const_preview($("#const_editor_name").val(), scalar, (scalar == 'string' ? '' : value));
    });
    $(document).on('keyup change', "#const_editor_value", function(){
        const_preview($("#const_editor_name").val(), $("#const_editor_scalar").val(), $("#const_editor_value").val());
    });
    function magic_const_preview(name, scalar, value){
        switch(scalar){
            case 'int':
                value = value.replace(/[^0-9]+/i, '') || 0;
                break;
            case 'float':
                value = value.replace(/[^0-9.]+/i, '') || 0;
                break;
            case 'bool':
                value = (value.toLowerCase() == 'true' || parseInt(value)) ? 'true' : 'false';
                break;
            case 'null':
                value = 'null';
                break;
        }
        $("#magic_const_editor_value").val(value);
        $("#magic_const_editor_preview").html(name ? (name.toUpperCase() + ' = ' + (scalar == 'string' ? "'" + value + "'" : value) + ';') : '');
    }
    $("#magic_const_editor_name").on('change', function(){
        magic_const_preview($("#magic_const_editor_name").val(), $("#magic_const_editor_scalar").val(), $("#magic_const_editor_value").val());
    });
    $("#magic_const_editor_scalar").on('change', function(){
        var scalar = $("#magic_const_editor_scalar").val(), v = $("#magic_const_editor_value"), value = v.val();
        if(scalar == 'bool'){
            v.replaceWith('<select id="magic_const_editor_value"><option value="true">true</option><option value="false">false</option></select>');
        } else if(scalar == 'null'){
            v.replaceWith('<input type="text" id="magic_const_editor_value" style="width: 100%;" value="" disabled="disabled"/>');
        } else {
            v.replaceWith('<input type="text" id="magic_const_editor_value" style="width: 100%;" value=""/>');
        }
        magic_const_preview($("#magic_const_editor_name").val(), scalar, (scalar == 'string' ? '' : value));
    });
    $(document).on('keyup change', "#magic_const_editor_value", function(){
        magic_const_preview($("#magic_const_editor_name").val(), $("#magic_const_editor_scalar").val(), $("#magic_const_editor_value").val());
    });
    function namespace_preview(name){
        $("#namespace_editor_preview").html(name ? ('namespace ' + name + ';') : '');
    }
    $("#namespace_editor_name").on('keyup', function(){
        $(this).val($(this).val().replace(/[^a-z0-9_\\]+/i, '_'));
        namespace_preview($("#namespace_editor_name").val());
    });
    function alias_preview(name, value){
        $("#alias_editor_preview").html(name ? ('use ' + name + (value ? ' as ' + value : '') + ';') : '');
    }
    $("#alias_editor_name, #alias_editor_value").on('keyup', function(){
        $(this).val($(this).val().replace(/[^a-z0-9_\\]+/i, '_'));
        alias_preview($("#alias_editor_name").val(), $("#alias_editor_value").val());
    });
    function class_preview(name, value){
        $("#class_editor_preview").html(name ? ('new ' + name + (value ? ' => new ' + value : '')) : '');
    }
    $("#class_editor_name, #class_editor_value").on('keyup', function(){
        $(this).val($(this).val().replace(/[^a-z0-9_\\]+/i, '_'));
        class_preview($("#class_editor_name").val(), $("#class_editor_value").val());
    });
    function interface_preview(name, value){
        $("#interface_editor_preview").html(name ? (name + (value ? ' => ' + value : '')) : '');
    }
    $("#interface_editor_name, #interface_editor_value").on('keyup', function(){
        $(this).val($(this).val().replace(/[^a-z0-9_\\]+/i, '_'));
        interface_preview($("#interface_editor_name").val(), $("#interface_editor_value").val());
    });
    function trait_preview(name, value){
        $("#trait_editor_preview").html(name ? (name + (value ? ' => ' + value : '')) : '');
    }
    $("#trait_editor_name, #trait_editor_value").on('keyup', function(){
        $(this).val($(this).val().replace(/[^a-z0-9_\\]+/i, '_'));
        trait_preview($("#trait_editor_name").val(), $("#trait_editor_value").val());
    });
    var func_editor;
    function launch_editor(type, el){
        var dialog = $("#" + type + "_editor_dialog"), buttons, delete_func = function(){
            if(el.parent().children('input').length < 2){
                el.parent().hide();
            }
            el.remove();
            $(this).dialog("close");
        };

        switch(type){
            case 'func':
                    buttons = {
                        "Save": function(){
                            var name = $("#func_editor_name").val(),
                                args = $("#func_editor_args").val(),
                                pass = $("#func_editor_pass").is(":checked") ? 1 : 0,
                                code = func_editor.getValue(),
                                button_name = name_button(name, "func"),
                                button = make_button(button_name, "func", "func", name),
                                list = $("#define_func");
                                button.data({"args": args, "code": code, "pass": pass, "fullcode": 'function(' + args + '){' + code + '}'});
                            if(el){
                                el.replaceWith(button);
                            } else {
                                list.append(button).show();
                            }
                            $(this).dialog("close");
                        }
                    };
                    if(el){
                        buttons["Delete"] = delete_func;
                    }
                dialog.dialog({
                    position: "center",
                    height: 580,
                    width: 800,
                    buttons: buttons,
                    close: function(){
                        $("#func_editor_name, #func_editor_args").val('');
                        $("#func_editor_pass").prop("checked", false);
                        $("#func_editor_preview").html('function (){');
                        $("#func_editor_dialog").hide().dialog("destroy");
                    }}).show();
                func_editor = ace.edit("func_editor");
                func_editor.setTheme("ace/theme/github");
                func_editor.getSession().setMode("ace/mode/php");
                func_editor.setValue('');
                func_editor.clearSelection();
                if(el){
                    var name = el.data('name'), args = el.data('args'), pass = el.data('pass'), code = el.data('code');
                    $("#func_editor_name").val(name);
                    $("#func_editor_args").val(args);
                    $("#func_editor_pass").prop("checked", pass ? true : false);
                    $("#func_editor_preview").html('function ' + name + '(' + args + '){');
                    func_editor.setValue(code);
                    func_editor.clearSelection();
                }
                break;

            case 'var':
                buttons = {
                    "Save": function(){
                        var name = $("#var_editor_name").val(),
                                scalar = $("#var_editor_scalar").val(),
                                value = $("#var_editor_value").val(),
                                button_name = name_button(name, "var"),
                                button = make_button(button_name, "var", "var", name),
                                list = $("#define_var");
                        switch(scalar){
                            case 'int':
                                value = parseInt(value) || 0;
                                break;
                            case 'float':
                                value = parseFloat(value) || 0;
                                break;
                            case 'bool':
                                value = (value.toLowerCase() == 'true' || parseInt(value)) ? true : false;
                                break;
                            case 'null':
                                value = null;
                                break;
                        }
                        button.data({"scalar": scalar, "value": value});
                        if(el){
                            el.replaceWith(button);
                        } else {
                            list.append(button).show();
                        }
                        $(this).dialog("close");
                    }
                };
                if(el){
                    buttons["Delete"] = delete_func;
                }
                dialog.dialog({
                    position: "center",
                    height: 300,
                    width: 400,
                    buttons: buttons,
                    close: function(){
                        $("#var_editor_name, #var_editor_value").val('');
                        $("#var_editor_scalar").val('string');
                        $("#var_editor_preview").html('');
                        $("#var_editor_dialog").hide().dialog("destroy");
                    }}).show();
                if(el){
                    var value = el.data('value');
                    if(value !== null){
                        value = value.toString();
                    }
                    $("#var_editor_name").val(el.data('name'));
                    $("#var_editor_scalar").val(el.data('scalar'));
                    $("#var_editor_value").val(value);
                    var_preview(el.data('name'), el.data('scalar'), value);
                }
                break;

            case 'superglobal':
                buttons = {
                    "Save": function(){
                        var name = $("#superglobal_editor_name").val(),
                                key = $("#superglobal_editor_key").val(),
                                scalar = $("#superglobal_editor_scalar").val(),
                                value = $("#superglobal_editor_value").val(),
                                button_name = name_button(name, "superglobal", key),
                                button = make_button(button_name, "superglobal", "superglobal", name),
                                list = $("#define_superglobal");
                        switch(scalar){
                            case 'int':
                                value = parseInt(value) || 0;
                                break;
                            case 'float':
                                value = parseFloat(value) || 0;
                                break;
                            case 'bool':
                                value = (value.toLowerCase() == 'true' || parseInt(value)) ? true : false;
                                break;
                            case 'null':
                                value = null;
                                break;
                        }
                        button.data({"key": key, "scalar": scalar, "value": value});
                        if(el){
                            el.replaceWith(button);
                        } else {
                            list.append(button).show();
                        }
                        $(this).dialog("close");
                    }
                };
                if(el){
                    buttons["Delete"] = delete_func;
                }
                dialog.dialog({
                    position: "center",
                    height: 360,
                    width: 400,
                    buttons: buttons,
                    close: function(){
                        $("#superglobal_editor_name").val('_GET');
                        $("#superglobal_editor_key, #superglobal_editor_value").val('');
                        $("#superglobal_editor_scalar").val('string');
                        $("#superglobal_editor_preview").html('');
                        $("#superglobal_editor_dialog").hide().dialog("destroy");
                    }}).show();
                if(el){
                    var value = el.data('value');
                    if(value !== null){
                        value = value.toString();
                    }
                    $("#superglobal_editor_name").val(el.data('name'));
                    $("#superglobal_editor_key").val(el.data('key'));
                    $("#superglobal_editor_scalar").val(el.data('scalar'));
                    $("#superglobal_editor_value").val(value);
                    superglobal_preview(el.data('name'), el.data('key'), el.data('scalar'), value);
                }
                break;

            case 'const':
                buttons = {
                    "Save": function(){
                        var name = $("#const_editor_name").val(),
                                scalar = $("#const_editor_scalar").val(),
                                value = $("#const_editor_value").val(),
                                button_name = name_button(name, "const"),
                                button = make_button(button_name, "const", "const", name),
                                list = $("#define_const");
                        switch(scalar){
                            case 'int':
                                value = parseInt(value) || 0;
                                break;
                            case 'float':
                                value = parseFloat(value) || 0;
                                break;
                            case 'bool':
                                value = (value.toLowerCase() == 'true' || parseInt(value)) ? true : false;
                                break;
                            case 'null':
                                value = null;
                                break;
                        }
                        button.data({"scalar": scalar, "value": value});
                        if(el){
                            el.replaceWith(button);
                        } else {
                            list.append(button).show();
                        }
                        $(this).dialog("close");
                    }
                };
                if(el){
                    buttons["Delete"] = delete_func;
                }
                dialog.dialog({
                    position: "center",
                    height: 300,
                    width: 400,
                    buttons: buttons,
                    close: function(){
                        $("#const_editor_name, #const_editor_value").val('');
                        $("#const_editor_scalar").val('string');
                        $("#const_editor_preview").html('');
                        $("#const_editor_dialog").hide().dialog("destroy");
                    }}).show();
                if(el){
                    var value = el.data('value');
                    if(value !== null){
                        value = value.toString();
                    }
                    $("#const_editor_name").val(el.data('name'));
                    $("#const_editor_scalar").val(el.data('scalar'));
                    $("#const_editor_value").val(value);
                    const_preview(el.data('name'), el.data('scalar'), value);
                }
                break;

            case 'magic_const':
                buttons = {
                    "Save": function(){
                        var name = $("#magic_const_editor_name").val(),
                                scalar = $("#magic_const_editor_scalar").val(),
                                value = $("#magic_const_editor_value").val(),
                                button_name = name_button(name, "magic_const"),
                                button = make_button(button_name, "magic_const", "magic_const", name),
                                list = $("#define_magic_const");
                        switch(scalar){
                            case 'int':
                                value = parseInt(value) || 0;
                                break;
                            case 'float':
                                value = parseFloat(value) || 0;
                                break;
                            case 'bool':
                                value = (value.toLowerCase() == 'true' || parseInt(value)) ? true : false;
                                break;
                            case 'null':
                                value = null;
                                break;
                        }
                        button.data({"scalar": scalar, "value": value});
                        if(el){
                            el.replaceWith(button);
                        } else {
                            list.append(button).show();
                        }
                        $(this).dialog("close");
                    }
                };
                if(el){
                    buttons["Delete"] = delete_func;
                }
                dialog.dialog({
                    position: "center",
                    height: 300,
                    width: 400,
                    buttons: buttons,
                    close: function(){
                        $("#magic_const_editor_name, #magic_const_editor_value").val('');
                        $("#magic_const_editor_scalar").val('string');
                        $("#magic_const_editor_preview").html('');
                        $("#magic_const_editor_dialog").hide().dialog("destroy");
                    }}).show();
                if(el){
                    var value = el.data('value');
                    if(value !== null){
                        value = value.toString();
                    }
                    $("#magic_const_editor_name").val(el.data('name'));
                    $("#magic_const_editor_scalar").val(el.data('scalar'));
                    $("#magic_const_editor_value").val(value);
                    magic_const_preview(el.data('name'), el.data('scalar'), value);
                }
                break;

            case 'namespace':
                buttons = {
                    "Save": function(){
                        var name = $("#namespace_editor_name").val(),
                                button_name = name_button(name, "namespace"),
                                button = make_button(button_name, "namespace", "namespace", name),
                                list = $("#define_namespace");
                        if(el){
                            el.replaceWith(button);
                        } else {
                            list.append(button).show();
                        }
                        $(this).dialog("close");
                    }
                };
                if(el){
                    buttons["Delete"] = delete_func;
                }
                dialog.dialog({
                    position: "center",
                    height: 300,
                    width: 400,
                    buttons: buttons,
                    close: function(){
                        $("#namespace_editor_name").val('');
                        $("#namespace_editor_preview").html('');
                        $("#namespace_editor_dialog").hide().dialog("destroy");
                    }}).show();
                if(el){
                    $("#namespace_editor_name").val(el.data('name'));
                    namespace_preview(el.data('name'));
                }
                break;

            case 'alias':
                buttons = {
                    "Save": function(){
                        var name = $("#alias_editor_name").val(),
                                value = $("#alias_editor_value").val(),
                                button_name = name_button(name, "alias", value),
                                button = make_button(button_name, "alias", "alias", name),
                                list = $("#define_alias");
                        button.data({"value": value});
                        if(el){
                            el.replaceWith(button);
                        } else {
                            list.append(button).show();
                        }
                        $(this).dialog("close");
                    }
                };
                if(el){
                    buttons["Delete"] = delete_func;
                }
                dialog.dialog({
                    position: "center",
                    height: 300,
                    width: 400,
                    buttons: buttons,
                    close: function(){
                        $("#alias_editor_name, #alias_editor_value").val('');
                        $("#alias_editor_preview").html('');
                        $("#alias_editor_dialog").hide().dialog("destroy");
                    }}).show();
                if(el){
                    var value = el.data('value');
                    if(value !== null){
                        value = value.toString();
                    }
                    $("#alias_editor_name").val(el.data('name'));
                    $("#alias_editor_value").val(value);
                    alias_preview(el.data('name'), value);
                }
                break;

            case 'class':
                buttons = {
                    "Save": function(){
                        var name = $("#class_editor_name").val(),
                                value = $("#class_editor_value").val(),
                                button_name = name_button(name, "class", value),
                                button = make_button(button_name, "class", "class", name),
                                list = $("#define_class");
                        button.data({"value": value});
                        if(el){
                            el.replaceWith(button);
                        } else {
                            list.append(button).show();
                        }
                        $(this).dialog("close");
                    }
                };
                if(el){
                    buttons["Delete"] = delete_func;
                }
                dialog.dialog({
                    position: "center",
                    height: 300,
                    width: 400,
                    buttons: buttons,
                    close: function(){
                        $("#class_editor_name, #class_editor_value").val('');
                        $("#class_editor_preview").html('');
                        $("#class_editor_dialog").hide().dialog("destroy");
                    }}).show();
                if(el){
                    var value = el.data('value');
                    if(value !== null){
                        value = value.toString();
                    }
                    $("#class_editor_name").val(el.data('name'));
                    $("#class_editor_value").val(value);
                    class_preview(el.data('name'), value);
                }
                break;

            case 'interface':
                buttons = {
                    "Save": function(){
                        var name = $("#interface_editor_name").val(),
                                value = $("#interface_editor_value").val(),
                                button_name = name_button(name, "interface", value),
                                button = make_button(button_name, "interface", "interface", name),
                                list = $("#define_interface");
                        button.data({"value": value});
                        if(el){
                            el.replaceWith(button);
                        } else {
                            list.append(button).show();
                        }
                        $(this).dialog("close");
                    }
                };
                if(el){
                    buttons["Delete"] = delete_func;
                }
                dialog.dialog({
                    position: "center",
                    height: 300,
                    width: 400,
                    buttons: buttons,
                    close: function(){
                        $("#interface_editor_name, #interface_editor_value").val('');
                        $("#interface_editor_preview").html('');
                        $("#interface_editor_dialog").hide().dialog("destroy");
                    }}).show();
                if(el){
                    var value = el.data('value');
                    if(value !== null){
                        value = value.toString();
                    }
                    $("#interface_editor_name").val(el.data('name'));
                    $("#interface_editor_value").val(value);
                    interface_preview(el.data('name'), value);
                }
                break;

            case 'trait':
                buttons = {
                    "Save": function(){
                        var name = $("#trait_editor_name").val(),
                                value = $("#trait_editor_value").val(),
                                button_name = name_button(name, "trait", value),
                                button = make_button(button_name, "trait", "trait", name),
                                list = $("#define_trait");
                        button.data({"value": value});
                        if(el){
                            el.replaceWith(button);
                        } else {
                            list.append(button).show();
                        }
                        $(this).dialog("close");
                    }
                };
                if(el){
                    buttons["Delete"] = delete_func;
                }
                dialog.dialog({
                    position: "center",
                    height: 300,
                    width: 400,
                    buttons: buttons,
                    close: function(){
                        $("#trait_editor_name, #trait_editor_value").val('');
                        $("#trait_editor_preview").html('');
                        $("#trait_editor_dialog").hide().dialog("destroy");
                    }}).show();
                if(el){
                    var value = el.data('value');
                    if(value !== null){
                        value = value.toString();
                    }
                    $("#trait_editor_name").val(el.data('name'));
                    $("#trait_editor_value").val(value);
                    trait_preview(el.data('name'), value);
                }
                break;
        }
    }
    $(function(){
        $("input.load").button().on('click', function(){
            $('#load').contents().find('input[name="load"]').click();
        });
        $("a.help").on('click', function(){
            $("#help_dialog").dialog({
                position: "center",
                width: 800,
                close: function(){
                    $("#help_dialog").hide().dialog("destroy");
                }
            }).show();
        });
    });
</script>
</body>
</html>