[
  {
    "path": ".gitignore",
    "content": "platform/config/local.js\nplatform/migrations/config.json\nplatform/public/css/*.css\nplatform/public/lib/webpack/*\n!platform/public/lib/webpack/.gitkeep\ncdn/avatars/*\n!cdn/avatars/.gitkeep\nvar/docker/mysql/*\n!var/docker/mysql/.gitkeep\nvar/docker/redis/*\n!var/docker/redis/.gitkeep\nvar/docker/logs/*\n!var/docker/logs/.gitkeep\nnode_modules\npackage-lock.json\n.env\n.DS_STORE\n.vscode\n"
  },
  {
    "path": ".prettierignore",
    "content": "platform/config/local.js\nplatform/migrations/config.json\nplatform/public/css/*.css\nplatform/public/lib\nplatform/resources/challenges/templates\ncdn/avatars/*\nvar/\nnode_modules\npackage-lock.json\n.env\n.DS_STORE\n.vscode\n"
  },
  {
    "path": ".prettierrc.json",
    "content": "{\n    \"tabWidth\": 4,\n    \"singleQuote\": true,\n    \"trailingComma\": \"none\"\n}\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM node:14.3.0-stretch\n\nRUN apt update && apt install -y inotify-tools libjson-c-dev\nRUN cd /opt && \\\n    wget https://github.com/realtux/rmig/releases/download/0.0.3/rmig-0.0.3-linux && \\\n    chmod +x rmig-0.0.3-linux && \\\n    ln -s /opt/rmig-0.0.3-linux /usr/bin/rmig\n\nWORKDIR /opt/emkc/platform\n\nCMD ./start\n"
  },
  {
    "path": "cdn/avatars/.gitkeep",
    "content": ""
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3'\nservices:\n    emkc:\n        container_name: emkc\n        build: .\n        ports:\n            - '2005:2727'\n        volumes:\n            - ./:/opt/emkc\n        environment:\n            APPENV: '${APPENV}'\n        restart: always\n        depends_on:\n            - redis\n            - mysql\n    redis:\n        container_name: emkc_redis\n        image: redis:3.2.12\n        volumes:\n            - ./:/opt/emkc\n            - ./var/docker/redis:/data\n        restart: always\n    mysql:\n        container_name: emkc_mysql\n        image: mysql:8\n        environment:\n            MYSQL_ROOT_PASSWORD: root\n            MYSQL_DATABASE: emkc\n        command: --init-file /var/lib/init/db.sql\n        volumes:\n            - ./:/opt/emkc\n            - ./var/docker/mysql:/var/lib/mysql\n            - ./var/docker/init:/var/lib/init\n            - ./var/docker/config:/etc/mysql/conf.d\n        restart: always\n"
  },
  {
    "path": "emkc",
    "content": "#!/usr/bin/env bash\n\nfunction init_files {\n    chmod 0444 var/docker/config/mysqld.cnf\n}\n\ncase $* in\n    init )\n        cp -n platform/config/local.js.sample platform/config/local.js\n        cp -n platform/migrations/config.json.sample platform/migrations/config.json\n        init_files\n        docker-compose build\n        docker-compose run --rm --no-deps emkc bash -c 'cd /opt/emkc/platform; npm install'\n        ;;\n    deploy )\n        git pull\n        docker-compose run --rm --no-deps emkc bash -c 'cd /opt/emkc/platform; npm install'\n        docker-compose down\n        docker-compose run --rm emkc bash -c 'cd /opt/emkc/platform/migrations; rmig migrate'\n        init_files\n        docker-compose up -d\n        ;;\n    start )\n        init_files\n        docker-compose up -d\n        ;;\n    stop )\n        docker-compose down\n        ;;\n    restart )\n        docker-compose restart\n        ;;\n    shell )\n        docker exec -it emkc /bin/bash\n        ;;\n    rebuild )\n        docker-compose build\n        ;;\n    npm )\n        docker-compose run --rm --no-deps emkc bash -c 'cd /opt/emkc/platform; npm install'\n        ;;\n    cron* )\n        docker-compose exec emkc bash -c \"/opt/emkc/platform/console/cron.js $2\"\n        ;;\n    mysql )\n        docker exec -it emkc_mysql bash -c 'mysql -hmysql -uroot -proot -Demkc'\n        ;;\n    rmig* )\n        docker exec -it emkc bash -c \"cd /opt/emkc/platform/migrations; $*\"\n        ;;\n    tail )\n        docker-compose logs -f\n        ;;\n    \"\" )\n        echo 'emkc control, usage: emkc [command]'\n        echo ''\n        echo 'init          initialize env specific config files'\n        echo 'start         start the emkc docker container'\n        echo 'stop          stop the emkc docker container'\n        echo 'restart       restart the docker containers'\n        echo 'shell         start a shell in the docker container'\n        echo 'rebuild       rebuild emkc from scratch'\n        echo 'npm           update node modules'\n        echo 'mysql         login to mysql'\n        echo 'rmig status   show the status of migrations'\n        echo 'rmig migrate  run the pending database migrations'\n        echo 'rmig rollback rollback one database migration'\n        echo 'tail          watch app and db logs'\n        exit 1\nesac\n"
  },
  {
    "path": "license",
    "content": "Copyright (c) 2018-2019 Brian Seymour, EMKC Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "package.json",
    "content": "{\n    \"scripts\": {\n        \"lint\": \"prettier --write .\",\n        \"check-lint\": \"prettier --check .\"\n    },\n    \"devDependencies\": {\n        \"prettier\": \"2.7.1\"\n    }\n}\n"
  },
  {
    "path": "platform/.babelrc",
    "content": "{\n    \"presets\": [\"@babel/preset-env\", \"@babel/preset-react\"],\n    \"plugins\": [\n        \"@babel/plugin-proposal-object-rest-spread\",\n        \"@babel/plugin-proposal-class-properties\",\n        \"@babel/plugin-transform-async-to-generator\"\n    ]\n}\n"
  },
  {
    "path": "platform/api/controllers/AuthController.js",
    "content": "const fs = require('fs');\nconst request = require('request-promise');\n\nmodule.exports = {\n    discord(req, res) {\n        // handle the redirect if one was passed with the login operation\n        if (req.query.r) {\n            req.session.redirect = req.query.r;\n        } else {\n            delete req.session.redirect;\n        }\n\n        return res.redirect(\n            'https://discord.com/api/v10/oauth2/authorize' +\n                '?client_id=' +\n                sails.config.discord.client_id +\n                '&redirect_uri=' +\n                encode_uri_component(constant.base_url + '/auth/discord_cb') +\n                '&response_type=code' +\n                '&scope=identify%20email'\n        );\n    },\n\n    async discord_cb(req, res) {\n        let code = req.query.code;\n\n        try {\n            // get an access token from the code returned from the authorization phase\n            let auth_result = await request({\n                method: 'post',\n                url: 'https://discord.com/api/v10/oauth2/token',\n                headers: {\n                    'content-type': 'application/x-www-form-urlencoded'\n                },\n                form: {\n                    code,\n                    client_id: sails.config.discord.client_id,\n                    client_secret: sails.config.discord.client_secret,\n                    grant_type: 'authorization_code',\n                    redirect_uri: constant.base_url + '/auth/discord_cb',\n                    scope: 'identify email'\n                },\n                json: true,\n                simple: true\n            });\n\n            // use the returned token to get the data of the user who just logged in\n            let discord_user = await request({\n                method: 'get',\n                url: 'https://discord.com/api/v10/users/@me',\n                headers: {\n                    Authorization: 'Bearer ' + auth_result.access_token\n                },\n                json: true,\n                simple: true\n            });\n\n            // add a new user record if there is not already one matching the given api id\n            let [user, created] = await db.users.find_or_create({\n                where: {\n                    discord_api: discord_user.id\n                },\n                defaults: {\n                    display_name: discord_user.username,\n                    email: discord_user.email || null\n                }\n            });\n\n            // if this is a new account, sort out what they're username should be\n            // usernames must be letter, numbers, underscores, and dashes only\n            // default username is new_guy and then a number which increases until one isn't used\n            if (created) {\n                let username = discord_user.username;\n                let ext = null;\n\n                username = username.replace(/[^0-9A-Za-z_\\-]+/gi, '');\n\n                if (username === '') username = 'new_guy';\n\n                // make sure username is unique\n                for (;;) {\n                    let dupe = await db.users.find_one({\n                        where: {\n                            user_id: {\n                                [$ne]: user.user_id\n                            },\n                            username: username + (ext === null ? '' : ext)\n                        }\n                    });\n\n                    if (!dupe) break;\n\n                    ext = ext === null ? 0 : ++ext;\n                }\n\n                // save the new username\n                user.username = username + (ext === null ? '' : ext);\n                await user.save();\n            }\n\n            if (user.display_name !== discord_user.username) {\n                user.display_name = discord_user.username;\n                await user.save();\n            }\n\n            // download discord avatar\n            request({\n                method: 'get',\n                url:\n                    'https://cdn.discordapp.com/avatars/' +\n                    discord_user.id +\n                    '/' +\n                    discord_user.avatar +\n                    '.png',\n                simple: true,\n                encoding: null\n            })\n                .then((res) => {\n                    fs.write_file(\n                        root_dir + '/cdn/avatars/' + user.user_id + '.png',\n                        res,\n                        () => {}\n                    );\n\n                    user.avatar_url = '/avatars/' + user.user_id + '.png';\n                    user.save();\n                })\n                .catch((err) => {});\n\n            // this logs the user in basically\n            req.session.user_id = user.user_id;\n\n            // add the emkc member role on discord\n            discord.api(\n                'put',\n                `/guilds/${constant.server_id}/members/${user.discord_api}/roles/${constant.roles.emkc_member}`\n            );\n\n            // according to whether or not the redirect was supplied, either go to that url or to board main\n            if (req.session.redirect) {\n                return res.redirect(req.session.redirect);\n                delete req.session.redirect;\n            } else {\n                return res.redirect('/');\n            }\n        } catch (e) {\n            return res.redirect('/');\n        }\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/ChallengesController.js",
    "content": "const fs = require('fs');\nconst util = require('util');\n\nmodule.exports = {\n    async home(req, res) {\n        let options = {\n            where: {\n                draft: 0\n            },\n            include: [\n                {\n                    required: false,\n                    model: db.user_challenges,\n                    as: 'solution',\n                    where: {\n                        user_id: req.local.user_id\n                    }\n                }\n            ],\n            order: [['challenge_id']],\n            group: 'challenge_id'\n        };\n\n        options.where.difficulty = constant.challenges.difficulty.easy;\n\n        let easy = await db.challenges.find_all(options);\n\n        options.where.difficulty = constant.challenges.difficulty.medium;\n\n        let medium = await db.challenges.find_all(options);\n\n        options.where.difficulty = constant.challenges.difficulty.hard;\n\n        let hard = await db.challenges.find_all(options);\n\n        return res.view({\n            easy,\n            medium,\n            hard\n        });\n    },\n\n    async choose_language(req, res) {\n        const { challenge_id } = req.params;\n\n        let challenge = await db.challenges.find_one({\n            where: {\n                challenge_id\n            },\n            include: [\n                {\n                    required: false,\n                    user_id: req.local.user_id,\n                    model: db.user_challenges,\n                    as: 'solutions',\n                    where: {\n                        user_id: req.local.user_id\n                    }\n                }\n            ]\n        });\n\n        if (!challenge) {\n            return res.redirect('back');\n        }\n\n        return res.view({\n            challenge,\n            solved: challenge.solutions.map((s) => s.language)\n        });\n    },\n\n    async challenge(req, res) {\n        const { challenge_id, language } = req.params;\n\n        if (!~constant.challenges.supported_languages.index_of(language)) {\n            return res.redirect('back');\n        }\n\n        let challenge = await db.challenges.find_one({\n            where: {\n                challenge_id\n            },\n            include: [\n                {\n                    required: false,\n                    model: db.user_challenges,\n                    as: 'solution',\n                    where: {\n                        user_id: req.local.user_id,\n                        language\n                    }\n                },\n                {\n                    required: false,\n                    model: db.challenge_tests,\n                    as: 'tests'\n                }\n            ]\n        });\n\n        if (!challenge || challenge.tests.length === 0) {\n            return res.redirect('back');\n        }\n\n        // unpack challenge assets\n        const read_file = util.promisify(fs.read_file);\n        const base_dir = root_dir + '/platform/resources/challenges';\n        const ext = {\n            js: 'js',\n            python: 'py',\n            go: 'go',\n            c: 'c',\n            ruby: 'rb',\n            cpp: 'cpp',\n            cs: 'cs',\n            php: 'php',\n            swift: 'swift',\n            java: 'java',\n            rust: 'rs',\n            julia: 'jl',\n            bash: 'sh',\n            perl: 'pl',\n            kotlin: 'kt',\n            haskell: 'hs',\n            nim: 'nim'\n        }[language];\n\n        const abstract = challenge.html;\n        let base_template = await read_file(\n            base_dir + '/templates/template.' + ext\n        );\n\n        let template = '';\n\n        base_template = base_template.to_string().split('\\n');\n\n        for (const line of base_template) {\n            // non processed line, add directly\n            if (!line.match(/^\\s*%%/gi)) {\n                template += line + '\\n';\n                continue;\n            }\n\n            // parse the input according to rules and return the first to determine template types\n            const { inputs } = test_cases.get_inputs_and_outputs(\n                challenge.tests[0]\n            );\n            let parsed_inputs = inputs.map((test_case) => {\n                return test_case.map((value) => {\n                    if (value.match(/^[0-9]+$/)) {\n                        return parse_int(value);\n                    }\n\n                    if (value.match(/^[0-9]+\\.[0-9]+$/)) {\n                        return parse_float(value);\n                    }\n\n                    return value;\n                });\n            })[0];\n\n            if (line.match(/^\\s*%%_IMPORTS_%%/gi)) {\n                let has_string = parsed_inputs.some(\n                    (input) => typeof input === 'string'\n                );\n                let has_int = parsed_inputs.some(\n                    (input) => typeof input === 'number'\n                );\n\n                switch (language) {\n                    case 'go':\n                        if (has_int) template += '    \"strconv\"\\n';\n                        break;\n                    case 'nim':\n                        if (has_int) template += 'import os, parseutils';\n                        else template += 'import os';\n\n                        template += '\\n\\n';\n\n                        break;\n                }\n\n                continue;\n            }\n\n            parsed_inputs.for_each((input, i) => {\n                ++i;\n                switch (language) {\n                    case 'c':\n                        if (typeof input === 'string')\n                            template += `    char value${i}[128]; strcpy(value${i}, argv[${i}]);`;\n                        if (typeof input === 'number')\n                            template += `    int value${i} = atoi(argv[${i}]);`;\n                        break;\n                    case 'cpp':\n                        if (typeof input === 'string')\n                            template += `    std::string value${i} = argv[${i}];`;\n                        if (typeof input === 'number')\n                            template += `    int value${i} = std::atoi(argv[${i}]);`;\n                        break;\n                    case 'cs':\n                        if (typeof input === 'string')\n                            template += `        string value${i} = args[${\n                                i - 1\n                            }];`;\n                        if (typeof input === 'number')\n                            template += `        int value${i} = Convert.ToInt32(args[${\n                                i - 1\n                            }]);`;\n                        break;\n                    case 'go':\n                        if (typeof input === 'string')\n                            template += `    var value${i} string = os.Args[${i}]`;\n                        if (typeof input === 'number')\n                            template += `    value${i}, _ := strconv.Atoi(os.Args[${i}])`;\n                        break;\n                    case 'java':\n                        if (typeof input === 'string')\n                            template += `        String value${i} = args[${\n                                i - 1\n                            }];`;\n                        if (typeof input === 'number')\n                            template += `        int value${i} = Integer.parseInt(args[${\n                                i - 1\n                            }]);`;\n                        break;\n                    case 'kotlin':\n                        if (typeof input === 'string')\n                            template += `    val value${i} = args[${i - 1}]`;\n                        if (typeof input === 'number')\n                            template += `    val value${i} = args[${\n                                i - 1\n                            }].toInt()`;\n                        break;\n                    case 'haskell':\n                        template += `    let value${i} = (args !! ${i - 1})`;\n                        break;\n                    case 'rust':\n                        if (typeof input === 'string')\n                            template += `    let value${i}: &String = &args[${i}];`;\n                        if (typeof input === 'number')\n                            template += `    let value${i}: i32 = args[${i}].parse().unwrap();`;\n                        break;\n                    case 'js':\n                        if (typeof input === 'string')\n                            template += `const value${i} = process.argv[${\n                                i + 1\n                            }];`;\n                        if (typeof input === 'number')\n                            template += `const value${i} = parseInt(process.argv[${\n                                i + 1\n                            }]);`;\n                        break;\n                    case 'php':\n                        template += `$value${i} = $argv[${i}];`;\n                        break;\n                    case 'python':\n                        if (typeof input === 'string')\n                            template += `value${i} = sys.argv[${i}]`;\n                        if (typeof input === 'number')\n                            template += `value${i} = int(sys.argv[${i}])`;\n                        break;\n                    case 'ruby':\n                        template += `value${i} = ARGV[${i - 1}]`;\n                        break;\n                    case 'swift':\n                        template += `var value${i} = CommandLine.arguments[${i}]`;\n                        break;\n                    case 'julia':\n                        if (typeof input === 'string')\n                            template += `value${i} = ARGS[${i}]`;\n                        if (typeof input === 'number')\n                            template += `value${i} = parse(Int, ARGS[${i}])`;\n                        break;\n                    case 'bash':\n                        template += `value${i}=$${i}`;\n                        break;\n                    case 'perl':\n                        template += `my $value${i} = $ARGV[${i - 1}];`;\n                        break;\n                    case 'nim':\n                        if (typeof input === 'number') {\n                            template += `var value${i}: int\\n`;\n                            template += `discard parseInt(paramStr(${i}), value${i})`;\n                        } else {\n                            template += `var value${i} = paramStr(${i})`;\n                        }\n\n                        break;\n                }\n                template += '\\n';\n            });\n        }\n\n        template = template.trim() + '\\n';\n\n        return res.view({\n            solved: !!challenge.solution,\n            challenge,\n            language,\n            abstract,\n            template,\n            monaco_language: {\n                js: 'javascript',\n                python: 'python',\n                go: 'go',\n                c: 'c',\n                ruby: 'ruby',\n                cpp: 'cpp',\n                cs: 'csharp',\n                php: 'php',\n                swift: 'swift',\n                java: 'java',\n                rust: 'rust',\n                julia: 'julia',\n                bash: 'shell',\n                perl: 'perl',\n                kotlin: 'kotlin',\n                haskell: 'haskell',\n                nim: 'nim'\n            }[language]\n        });\n    },\n\n    async execute(req, res) {\n        const { challenge_id } = req.params;\n        const { language, source } = req.body;\n\n        let challenge = await db.challenges.find_one({\n            where: {\n                challenge_id\n            },\n            include: {\n                required: false,\n                model: db.challenge_tests,\n                as: 'tests'\n            }\n        });\n\n        if (challenge.tests.length === 0) {\n            return res.status(400).send();\n        }\n\n        const results = [];\n\n        for (const test of challenge.tests) {\n            const { inputs, outputs } = test_cases.get_inputs_and_outputs(test);\n            let test_idx = Math.floor(Math.random() * inputs.length);\n\n            let result = await piston.execute(\n                language,\n                source,\n                inputs[test_idx],\n                '',\n                '*'\n            );\n            const compile_output = result.compile && result.compile.output;\n            const run_error = result.run.stderr;\n            const run_output = result.run.stdout.trim();\n\n            results.push({\n                name: test.name,\n                passed: run_output === outputs[test_idx],\n                input: inputs[test_idx],\n                expected: outputs[test_idx],\n                actual: run_output,\n                compile_output,\n                run_error\n            });\n        }\n\n        const passed = results.filter((r) => !r.passed).length === 0;\n\n        if (passed && req.local.user_id && !challenge.draft) {\n            set_immediate(async () => {\n                let [user_challenge, created] =\n                    await db.user_challenges.find_or_create({\n                        where: {\n                            user_id: req.local.user_id,\n                            challenge_id: challenge.challenge_id,\n                            language\n                        },\n                        defaults: {\n                            solution: source\n                        }\n                    });\n\n                if (created) {\n                    return null;\n                }\n\n                user_challenge.solution = source;\n                user_challenge.save();\n            });\n        }\n\n        return res.status(200).send(results);\n    },\n\n    async view_other(req, res) {\n        const { username, challenge_id, language } = req.params;\n\n        let user = await db.users.find_one({\n            where: {\n                username\n            }\n        });\n\n        if (!user) throw null;\n\n        let user_solution = await db.user_challenges.find_one({\n            where: {\n                user_id: req.local.user_id,\n                challenge_id,\n                language\n            }\n        });\n\n        if (!user_solution) {\n            return res.redirect('back');\n        }\n\n        let challenge = await db.user_challenges.find_one({\n            where: {\n                user_id: user.user_id,\n                challenge_id,\n                language\n            },\n            include: [\n                {\n                    model: db.challenges,\n                    as: 'challenge'\n                }\n            ],\n            order: [['created_at', 'desc']]\n        });\n\n        if (challenge) {\n            return res.view('snippets/edit', {\n                snippet: {\n                    language,\n                    snip: challenge.solution\n                },\n                mode: 'view'\n            });\n        }\n\n        return res.redirect('/snippets');\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/CommunityController.js",
    "content": "module.exports = {\n    home(req, res) {\n        return res.view();\n    },\n\n    about(req, res) {\n        return res.view();\n    },\n\n    power(req, res) {\n        return res.view();\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/ContestsController.js",
    "content": "const moment = require('moment');\n\nmodule.exports = {\n    async home(req, res) {\n        let past_contests = await db.contests.find_all({\n            where: {\n                end_date: {\n                    [$lt]: util.now()\n                }\n            },\n            order: [['end_date', 'desc']]\n        });\n\n        let past_submissions = await db.contest_submissions.find_all({\n            where: {\n                contest_id: past_contests.map((contest) => contest.contest_id)\n            },\n            attributes: ['contest_id'],\n            include: [\n                {\n                    model: db.users,\n                    as: 'user',\n                    attributes: ['avatar_url']\n                }\n            ]\n        });\n\n        let submission_map = {};\n\n        for (const submission of past_submissions) {\n            if (!submission_map[submission.contest_id]) {\n                submission_map[submission.contest_id] = [];\n            }\n\n            submission_map[submission.contest_id].push(\n                submission.user.avatar_url\n            );\n        }\n\n        for (const contest of past_contests) {\n            contest.solutions = submission_map[contest.contest_id]\n                ? submission_map[contest.contest_id].length\n                : 0;\n\n            contest.participants = [\n                ...new Set(submission_map[contest.contest_id] || [])\n            ];\n        }\n\n        let active_contests = await db.contests.find_all({\n            where: {\n                start_date: {\n                    [$lte]: util.now()\n                },\n                end_date: {\n                    [$gte]: util.now()\n                }\n            },\n            include: [\n                {\n                    model: db.contest_submissions,\n                    as: 'submissions',\n                    include: [\n                        {\n                            model: db.users,\n                            as: 'user'\n                        }\n                    ]\n                }\n            ],\n            order: [\n                ['end_date', 'desc'],\n                [\n                    { model: db.contest_submissions, as: 'submissions' },\n                    'created_at'\n                ]\n            ]\n        });\n\n        return res.view({\n            past_contests,\n            active_contests\n        });\n    },\n\n    async contest(req, res) {\n        const { contest_id, slug } = req.params;\n\n        let contest = await db.contests.find_one({\n            where: {\n                contest_id\n            },\n            include: [\n                {\n                    model: db.contest_submissions,\n                    as: 'submissions',\n                    attributes: [\n                        'contest_submission_id',\n                        'user_id',\n                        'language',\n                        'language_version',\n                        'solution',\n                        'length',\n                        'explanation',\n                        'created_at',\n                        'late'\n                    ],\n                    include: [\n                        {\n                            model: db.users,\n                            as: 'user',\n                            attributes: ['username', 'avatar_url']\n                        }\n                    ]\n                }\n            ],\n            order: [\n                [\n                    { model: db.contest_submissions, as: 'submissions' },\n                    'length'\n                ],\n                [\n                    { model: db.contest_submissions, as: 'submissions' },\n                    'created_at'\n                ]\n            ]\n        });\n\n        if (!contest || slug !== contest.slug) {\n            return res.redirect('/contests');\n        }\n\n        let awarded_languages = [];\n        let awarded_users = [];\n        let top = 1;\n\n        let cases = contests.get_cases(contest, true);\n\n        contest.submissions.for_each((submission, i) => {\n            // overall awards for top 3 solutions submitted by unique users\n            if (\n                !submission.late &&\n                !awarded_users.includes(submission.user_id) &&\n                top <= 3\n            ) {\n                switch (top) {\n                    case 1:\n                        submission.dataValues.overall_first = true;\n                        break;\n                    case 2:\n                        submission.dataValues.overall_second = true;\n                        break;\n                    case 3:\n                        submission.dataValues.overall_third = true;\n                        break;\n                }\n\n                awarded_users.push(submission.user_id);\n\n                ++top;\n            }\n\n            // per language awards for top solution in each language\n            if (\n                !submission.late &&\n                !awarded_languages.includes(submission.language)\n            ) {\n                submission.dataValues.language_first = true;\n                awarded_languages.push(submission.language);\n            }\n\n            // hide the solution in the payload to prevent cheating\n            if (contest.active) {\n                delete submission.dataValues.explanation;\n                delete submission.dataValues.solution;\n            }\n        });\n\n        let submissions = await db.contest_submissions.find_all({\n            where: {\n                contest_id,\n                user_id: req.local.user_id\n            }\n        });\n\n        return res.view({\n            contest,\n            cases,\n            submissions\n        });\n    },\n\n    async submit(req, res) {\n        let { contest_id, language, solution, explanation, language_version } =\n            req.body;\n\n        explanation = explanation || '';\n        solution = solution.trim();\n\n        let contest = await db.contests.find_one({\n            where: {\n                contest_id\n            }\n        });\n\n        let test_cases = contests.get_cases(contest);\n        if (test_cases.length === 0) {\n            return res.status(400).send({\n                message:\n                    'No test cases exit for this contest, please contact an administrator'\n            });\n        }\n        let languages = await piston.runtimes();\n\n        languages = languages.filter((lang) => lang.language === language);\n\n        // To prevent submissions by alias\n        if (\n            constant.contests.disallowed_languages.includes(language) ||\n            !languages.length\n        ) {\n            return res.status(400).send({\n                message: 'An error has occurred while submitting your solution'\n            });\n        }\n\n        let is_valid = await contests.validate_submission(\n            test_cases,\n            solution,\n            language,\n            language_version\n        );\n\n        if (!is_valid) {\n            return res.status(200).send({\n                passed: false\n            });\n        }\n\n        if (moment().isBefore(contest.start_date)) {\n            // Don't save solution for upcoming contests\n            return res.status(200).send({\n                passed: true\n            });\n        }\n\n        let submission = await db.contest_submissions.find_one({\n            where: {\n                contest_id,\n                language,\n                user_id: req.local.user_id,\n                late: contest.active ? 0 : 1\n            }\n        });\n\n        let solution_bytes = new TextEncoder().encode(solution).length;\n\n        if (submission) {\n            submission.language = language;\n            submission.solution = solution;\n            submission.length = solution_bytes;\n            submission.explanation = explanation;\n            submission.language_version = language_version;\n\n            let prev_length = submission.previous('length');\n            let prev_length_best = submission.previous('length_best');\n\n            if (submission.length < prev_length_best) {\n                submission.length_best = solution_bytes;\n                submission.created_at = util.now();\n            }\n\n            if (submission.length < prev_length && contest.active) {\n                discord\n                    .api(\n                        'post',\n                        `/channels/${constant.channels.emkc}/messages`,\n                        {\n                            embeds: [\n                                {\n                                    title: contest.name,\n                                    description:\n                                        `Can you do better than this? ` +\n                                        `[Click here](${constant.base_url}${contest.url}) to give it a try.`,\n                                    type: 'rich',\n                                    color: 0x84e47f,\n                                    timestamp: moment().toISOString(),\n                                    url: `${constant.base_url}${contest.url}`,\n                                    author: {\n                                        name:\n                                            `${req.local.user.display_name} updated their ${submission.language} ${submission.language_version} solution ` +\n                                            `with one that is ${submission.length} bytes large ` +\n                                            `(a ${\n                                                prev_length - submission.length\n                                            } byte improvement)`\n                                    },\n                                    footer: {\n                                        icon_url:\n                                            constant.cdn_url +\n                                            req.local.user.avatar_url,\n                                        text: `updated by ${req.local.user.display_name}`\n                                    }\n                                }\n                            ]\n                        }\n                    )\n                    .catch((err) => {});\n            }\n\n            await submission.save();\n        } else {\n            submission = await db.contest_submissions.create({\n                user_id: req.local.user_id,\n                contest_id,\n                language,\n                language_version,\n                solution,\n                length: solution_bytes,\n                length_best: solution_bytes,\n                explanation,\n                late: !contest.active\n            });\n\n            if (contest.active) {\n                discord\n                    .api(\n                        'post',\n                        `/channels/${constant.channels.emkc}/messages`,\n                        {\n                            embeds: [\n                                {\n                                    title: contest.name,\n                                    description:\n                                        `Can you make a better solution? ` +\n                                        `[Click here](${constant.base_url}${contest.url}) to give it a try.`,\n                                    type: 'rich',\n                                    color: 0x84e47f,\n                                    timestamp: moment().toISOString(),\n                                    url: `${constant.base_url}${contest.url}`,\n                                    author: {\n                                        name:\n                                            `${req.local.user.display_name} submitted an initial ${submission.length} ` +\n                                            `byte solution with ${submission.language} ${submission.language_version}`\n                                    },\n                                    footer: {\n                                        icon_url:\n                                            constant.cdn_url +\n                                            req.local.user.avatar_url,\n                                        text: `submitted by ${req.local.user.display_name}`\n                                    }\n                                }\n                            ]\n                        }\n                    )\n                    .catch((err) => {});\n            }\n        }\n\n        return res.status(200).send({\n            passed: true\n        });\n    },\n\n    async disallowed_languages(req, res) {\n        let { contest_id } = req.params;\n\n        let contest = await db.contests.find_one({\n            where: {\n                contest_id\n            }\n        });\n\n        let disallowed_languages = contest.disallowed_languages\n            ? contest.disallowed_languages.split(',')\n            : [];\n\n        return res.status(200).send(disallowed_languages);\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/HomeController.js",
    "content": "module.exports = {\n    async home(req, res) {\n        let users = await db.users.find_all({\n            order: [['score', 'desc'], ['user_id']],\n            limit: 100\n        });\n\n        return res.view({\n            users\n        });\n    },\n\n    privacy(req, res) {\n        return res.view();\n    },\n\n    login() {\n        return res.view();\n    },\n\n    async logout_as(req, res) {\n        if (!req.session.old_id) {\n            // Logging back from nothing\n            return res.view('home/fourohfour');\n        }\n\n        req.session.user_id = req.session.old_id;\n        delete req.session.old_id;\n\n        return res.redirect('/');\n    },\n\n    logout(req, res) {\n        delete req.session.user_id;\n        return res.redirect('back');\n    },\n\n    fourohfour(req, res) {\n        return res.status(404).view('home/fourohfour');\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/MerchController.js",
    "content": "const moment = require('moment');\n\nmodule.exports = {\n    stickers(req, res) {\n        return res.view({\n            options: [\n                { quantity: 2, cost: 'FREE' },\n                { quantity: 3, cost: '2.40' },\n                { quantity: 5, cost: '3.50' },\n                { quantity: 10, cost: '6.00' }\n            ]\n        });\n    },\n\n    async order_stickers(req, res) {\n        const { tx, quantity, name, email, address, coupon } = req.body;\n\n        if (!coupon && !tx) {\n            return res.status(400).send();\n        }\n\n        let order = await db.sticker_orders.create({\n            tx,\n            coupon,\n            quantity,\n            cost: {\n                2: null,\n                3: 2.4,\n                5: 3.5,\n                10: 6.0\n            }[quantity],\n            name,\n            email,\n            address,\n            created_at: moment()\n        });\n\n        return res.status(200).send({\n            order_id: order.sticker_order_id\n        });\n    },\n\n    check_code(req, res) {\n        return res.status(200).send({\n            valid:\n                req.params.code.to_upper_case() === sails.config.paypal.coupon\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/ProfilesController.js",
    "content": "module.exports = {\n    async view(req, res) {\n        const username = req.params.username;\n\n        let user = await db.users.find_one({\n            where: {\n                username\n            }\n        });\n\n        if (!user) {\n            return res.redirect('/');\n        }\n\n        let stat_challenges = await db.challenges.find_all({\n            include: [\n                {\n                    model: db.user_challenges,\n                    as: 'solutions',\n                    where: {\n                        user_id: user.user_id\n                    }\n                }\n            ]\n        });\n\n        let stat_contests = await db.contests.find_all({\n            include: [\n                {\n                    model: db.contest_submissions,\n                    as: 'submissions',\n                    where: {\n                        user_id: user.user_id\n                    }\n                }\n            ]\n        });\n\n        let awards = await db.awards.find_all({\n            where: {\n                user_id: user.user_id\n            },\n            order: [['type']]\n        });\n\n        awards = awards.reduce((a, c) => {\n            let entry = a.find((e) => e.type === c.type);\n\n            if (entry) {\n                ++entry.count;\n            } else {\n                a.push({\n                    type: c.type,\n                    count: 1,\n                    tooltip_text: c.tooltip_text\n                });\n            }\n\n            return a;\n        }, []);\n\n        let challenges = await db.user_challenges.find_all({\n            where: {\n                user_id: user.user_id\n            },\n            include: [\n                {\n                    model: db.challenges,\n                    as: 'challenge'\n                }\n            ],\n            order: [['created_at', 'desc']],\n            limit: 5\n        });\n\n        let user_solved_challenges = await db.user_challenges.find_all({\n            where: {\n                user_id: req.local.user_id\n            },\n            include: [\n                {\n                    model: db.challenges,\n                    as: 'challenge'\n                }\n            ],\n            order: [['created_at', 'desc']]\n        });\n\n        return res.view({\n            user,\n            stat_challenges: stat_challenges.length,\n            stat_contests: stat_contests.length,\n            awards,\n            challenges,\n            user_solved_challenges: user_solved_challenges.map((challenge) => {\n                return {\n                    challenge_id: challenge.challenge_id,\n                    language: challenge.language\n                };\n            })\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/ScriptsController.js",
    "content": "module.exports = {\n    async home(req, res) {\n        let scripts = await db.cli_scripts.find_all({\n            where: {\n                is_safe: constant.yes\n            }\n        });\n\n        return res.view({\n            scripts\n        });\n    },\n\n    async view(req, res) {\n        const cli_script_id = req.params.cli_script_id;\n\n        let script = await db.cli_scripts.find_one({\n            where: {\n                cli_script_id\n            }\n        });\n\n        return res.view({\n            script\n        });\n    },\n\n    async exec(req, res) {\n        const cli_script_id = req.params.cli_script_id;\n\n        let script = await db.cli_scripts.find_one({\n            where: {\n                cli_script_id\n            }\n        });\n\n        res.set('content-type', 'text/plain');\n\n        return res.status(200).send(script.content);\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/SnippetsController.js",
    "content": "module.exports = {\n    async view(req, res) {\n        const { hash } = req.params;\n\n        let snippet = await db.snippets.find_one({\n            where: {\n                hash\n            }\n        });\n\n        try {\n            if (!snippet) {\n                throw null;\n            }\n\n            if (\n                req.headers.accept === 'text/plain' ||\n                req.path.match(/\\/raw$/)\n            ) {\n                res.set('content-type', 'text/plain');\n\n                return res.status(200).send(snippet.snip);\n            }\n\n            if (req.headers.accept === 'application/json') {\n                return res.status(200).send(snippet);\n            }\n\n            return res.view('snippets/edit', {\n                mode: 'view',\n                snippet\n            });\n        } catch (e) {\n            return res.redirect('/snippets');\n        }\n    },\n\n    async mine(req, res) {\n        let snippets = await db.snippets.find_all({\n            where: {\n                user_id: req.local.user_id\n            },\n            order: [['snippet_id', 'desc']]\n        });\n\n        return res.view({\n            snippets\n        });\n    },\n\n    async create(req, res) {\n        if (req.method === 'POST') {\n            const { language, snip } = req.body;\n\n            try {\n                if (!snip) {\n                    throw new Error('Please supply some code');\n                }\n\n                let snippet = await db.snippets.create({\n                    user_id: req.local.user_id,\n                    language,\n                    snip\n                });\n\n                return res.status(200).send({\n                    url: snippet.url\n                });\n            } catch (e) {\n                return res.status(400).send({\n                    message: e.message\n                });\n            }\n        }\n\n        return res.view('snippets/edit', {\n            mode: 'create',\n            snippet: {\n                language: '',\n                snip: '',\n                hash: ''\n            }\n        });\n    },\n\n    async delete(req, res) {\n        const { hash } = req.params;\n\n        let snippet = await db.snippets.find_one({\n            where: {\n                hash,\n                user_id: req.local.user_id\n            }\n        });\n\n        if (snippet) {\n            await snippet.destroy();\n        }\n\n        return res.status(snippet ? 200 : 400).send({\n            url: '/snippets/mine'\n        });\n    },\n\n    async edit(req, res) {\n        const { hash } = req.params;\n\n        let snippet = await db.snippets.find_one({\n            where: {\n                hash,\n                user_id: req.local.user_id\n            }\n        });\n\n        if (req.method === 'POST') {\n            const { language, snip } = req.body;\n\n            try {\n                if (!snippet) {\n                    return res.status(400).send({\n                        url: '/snippets'\n                    });\n                }\n\n                if (!snip) {\n                    throw new Error('Please supply some code');\n                }\n\n                snippet.language = language;\n                snippet.snip = snip;\n                await snippet.save();\n\n                return res.status(200).send({\n                    url: snippet.url\n                });\n            } catch (e) {\n                return res.status(400).send({\n                    message: e.message\n                });\n            }\n        }\n\n        if (!snippet) {\n            return res.redirect('/snippets');\n        }\n\n        return res.view({\n            mode: 'update',\n            snippet\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/TagsController.js",
    "content": "module.exports = {\n    async search(req, res) {\n        const name = req.query.name;\n\n        let tags = await db.tags.find_all({\n            where: {\n                name: {\n                    [$like]: '%' + name + '%'\n                }\n            },\n            order: [['name']],\n            limit: 10\n        });\n\n        return res.send({\n            status: 'ok',\n            payload: {\n                tags: name ? tags : []\n            }\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/admin/ChallengesController.js",
    "content": "const create_tests = async (tests) => {\n    for (const test of tests) {\n        const { challenge_id, name, input, output } = test;\n        await db.challenge_tests.create({ challenge_id, name, input, output });\n    }\n};\n\nconst unify_tests_challenge_id = (tests, challenge_id) => {\n    for (const test of tests) {\n        test.challenge_id = challenge_id;\n    }\n};\n\nconst find_invalid_test = (tests) => {\n    for (const test of tests) {\n        if (!test_cases.are_valid(test)) {\n            return test;\n        }\n    }\n    return null;\n};\n\nconst get_tests_errors = (tests) => {\n    if (tests.length === 0) {\n        return 'The challenge tests can not be empty';\n    }\n    const invalid_test = find_invalid_test(tests);\n    if (invalid_test !== null) {\n        return `Invalid test cases in ${invalid_test.name} test`;\n    }\n    return null;\n};\n\nmodule.exports = {\n    async view_all(req, res) {\n        let challenges = await db.challenges.find_all({\n            order: [['challenge_id', 'desc']]\n        });\n\n        return res.view({\n            challenges\n        });\n    },\n\n    async create(req, res) {\n        if (req.method === 'POST') {\n            try {\n                const {\n                    draft,\n                    difficulty,\n                    points,\n                    name,\n                    description,\n                    html,\n                    tests\n                } = req.body;\n\n                const created_challenge = await db.challenges.create({\n                    draft,\n                    difficulty,\n                    points,\n                    name,\n                    description,\n                    html\n                });\n\n                unify_tests_challenge_id(tests, created_challenge.challenge_id);\n                const error_message = get_tests_errors(tests);\n                if (error_message !== null) {\n                    await created_challenge.destroy();\n                    return res.status(400).send({\n                        message: error_message\n                    });\n                }\n                create_tests(tests);\n                return res.status(200).send();\n            } catch (e) {\n                return res.status(400).send();\n            }\n        }\n\n        return res.view('admin/challenges/update', {\n            mode: 'create',\n            challenge: {\n                difficulty: 1,\n                draft: true,\n                points: 10,\n                name: '',\n                description: '',\n                html: '',\n                tests: []\n            }\n        });\n    },\n\n    async update(req, res) {\n        const { challenge_id } = req.params;\n\n        let existing_challenge = await db.challenges.find_one({\n            where: {\n                challenge_id\n            },\n            include: [\n                {\n                    required: false,\n                    model: db.challenge_tests,\n                    as: 'tests'\n                }\n            ]\n        });\n\n        if (!existing_challenge) {\n            return res.redirect('back');\n        }\n\n        if (req.method === 'POST') {\n            const {\n                draft,\n                difficulty,\n                points,\n                name,\n                description,\n                html,\n                tests\n            } = req.body;\n            const challenge = {\n                draft,\n                difficulty,\n                points,\n                name,\n                description,\n                html\n            };\n            for (const attr in challenge) {\n                existing_challenge[attr] = challenge[attr];\n            }\n            try {\n                unify_tests_challenge_id(\n                    tests,\n                    existing_challenge.challenge_id\n                );\n                const error_message = get_tests_errors(tests);\n                if (error_message !== null) {\n                    return res.status(400).send({\n                        message: error_message\n                    });\n                }\n                await existing_challenge.save();\n                await db.challenge_tests.destroy({\n                    where: { challenge_id: existing_challenge.challenge_id }\n                });\n                create_tests(tests);\n                return res.status(200).send();\n            } catch (e) {\n                return res.status(400).send();\n            }\n        }\n\n        return res.view({\n            mode: 'update',\n            challenge: existing_challenge\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/admin/ContestsController.js",
    "content": "const moment = require('moment');\n\nmodule.exports = {\n    async view_all(req, res) {\n        let all_contests = await db.contests.find_all({\n            order: [['contest_id', 'desc']]\n        });\n\n        return res.view({\n            contests: all_contests\n        });\n    },\n\n    async create(req, res) {\n        if (req.method === 'POST') {\n            const {\n                name,\n                description,\n                start_date,\n                end_date,\n                input,\n                output,\n                disallowed_languages\n            } = req.body;\n\n            if (!test_cases.are_valid({ input, output })) {\n                return res.status(400).send({ message: 'Invalid test cases' });\n            }\n\n            await db.contests.create({\n                name,\n                description,\n                start_date,\n                end_date,\n                input,\n                output,\n                disallowed_languages\n            });\n\n            return res.status(200).send();\n        }\n        let disallowed_languages =\n            constant.contests.disallowed_languages.join(',');\n\n        return res.view('admin/contests/update', {\n            mode: 'create',\n            contest: {\n                name: '',\n                description: '',\n                start_date: moment()\n                    .startOf('isoweek')\n                    .add(6, 'days')\n                    .format('YYYY-MM-DD 17:00:00'),\n                end_date: moment()\n                    .startOf('isoweek')\n                    .add(9, 'days')\n                    .format('YYYY-MM-DD 17:00:00'),\n                input: '',\n                output: '',\n                disallowed_languages\n            }\n        });\n    },\n\n    async update(req, res) {\n        const contest_id = req.params.contest_id;\n\n        let contest = await db.contests.find_one({\n            where: {\n                contest_id\n            }\n        });\n\n        if (req.method === 'POST') {\n            const {\n                name,\n                description,\n                start_date,\n                end_date,\n                input,\n                output,\n                disallowed_languages\n            } = req.body;\n\n            if (!test_cases.are_valid({ input, output })) {\n                return res.status(400).send({ message: 'Invalid test cases' });\n            }\n\n            contest.name = name;\n            contest.description = description;\n            contest.start_date = start_date;\n            contest.end_date = end_date;\n            contest.input = input;\n            contest.output = output;\n            contest.disallowed_languages = disallowed_languages;\n\n            await contest.save();\n\n            return res.status(200).send();\n        }\n\n        return res.view({\n            contest,\n            mode: 'update'\n        });\n    },\n\n    async delete_submission(req, res) {\n        const { contest_submission_id } = req.body;\n\n        let submission = await db.contest_submissions.find_one({\n            where: {\n                contest_submission_id\n            }\n        });\n\n        if (!submission) {\n            return res.status(400).send();\n        }\n\n        await submission.destroy();\n\n        return res.status(200).send();\n    },\n\n    async validate_submissions(req, res) {\n        const { contest_id } = req.params;\n\n        let contest = await db.contests.find_one({\n            where: {\n                contest_id\n            },\n            include: [\n                {\n                    required: false,\n                    model: db.contest_submissions,\n                    as: 'submissions',\n                    include: [\n                        {\n                            model: db.users,\n                            as: 'user',\n                            attributes: ['username']\n                        }\n                    ]\n                }\n            ]\n        });\n\n        let test_cases = contests.get_cases(contest);\n\n        let invalids = [];\n        const CHUNK_SIZE = 5;\n        let validation_ops = [];\n        for (let count = 1; count <= contest.submissions.length; ++count) {\n            const submission = contest.submissions[count - 1];\n            validation_ops.push(\n                contests\n                    .validate_submission(\n                        test_cases,\n                        submission.solution,\n                        submission.language,\n                        submission.language_version || '*'\n                    )\n                    .then((valid) => {\n                        if (!valid) invalids.push(submission);\n                    })\n            );\n            if (\n                count % CHUNK_SIZE === 0 ||\n                count === contest.submissions.length\n            ) {\n                await Promise.all(validation_ops);\n                validation_ops = [];\n            }\n        }\n\n        return res.status(200).send({\n            invalids\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/admin/DashboardController.js",
    "content": "module.exports = {\n    async dashboard(req, res) {\n        return res.view();\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/admin/PistonController.js",
    "content": "module.exports = {\n    async view_all(req, res) {\n        return res.view({\n            message: null\n        });\n    },\n\n    async packages(req, res) {\n        let packages = await piston.packages();\n\n        return res.status(200).send(packages);\n    },\n\n    async install(req, res) {\n        let { language, version } = req.query;\n\n        let result = await piston.install(language, version);\n\n        let message = result.language\n            ? 'succeeded'\n            : 'failed: ' + result.message;\n\n        return res.view('admin/piston/view_all', {\n            message: `Installation of ${language}-${version} ${message}`\n        });\n    },\n\n    async uninstall(req, res) {\n        let { language, version } = req.query;\n\n        let result = await piston.uninstall(language, version);\n\n        let message = result.language\n            ? 'succeeded'\n            : 'failed: ' + result.message;\n\n        return res.view('admin/piston/view_all', {\n            message: `Uninstallation of ${language}-${version} ${message}`\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/admin/UsersController.js",
    "content": "module.exports = {\n    async view_all(req, res) {\n        let users = await db.users.find_all({\n            attributes: ['user_id', 'username', 'display_name', 'created_at'],\n            where: {\n                [$not]: {\n                    user_id: req.session.user_id\n                }\n            },\n            order: [['user_id', 'desc']]\n        });\n\n        return res.view({\n            users\n        });\n    },\n\n    async login_as(req, res) {\n        let target_id = parse_int(req.query.user_id);\n\n        let user = await db.users.find_one({\n            where: {\n                user_id: target_id\n            }\n        });\n\n        // The logging in logic\n        if (req.session.user_id === target_id || req.session.old_id || !user) {\n            // On trying to log in as oneself or not using the original user\n            return res.view('home/fourohfour');\n        }\n\n        req.session.old_id = req.session.user_id;\n        req.session.user_id = target_id;\n\n        return res.redirect('/');\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/api/internal/ChatsController.js",
    "content": "const crypto = require('crypto');\nconst moment = require('moment');\n\nmodule.exports = {\n    async last(req, res) {\n        let message = await db.discord_chat_messages.find_one({\n            order: [['created_at', 'desc']]\n        });\n\n        // this should only be a thing once, send beginning of time\n        if (!message) {\n            return res.send({\n                last_timestamp: moment('1970-01-01').format()\n            });\n        }\n\n        return res.status(200).send({\n            last_timestamp: message.created_at\n        });\n    },\n\n    async create(req, res) {\n        let messages = req.body;\n\n        // sometimes only a single message object will be sent, transparently convert to array\n        if (!Array.is_array(messages)) messages = [messages];\n\n        let inserted = 0;\n        let duplicate = 0;\n        let failed = 0;\n\n        // filter out any messages that don't have all the necessary information\n        messages = messages.filter((m) => {\n            let valid =\n                m.channel &&\n                m.user &&\n                m.discord_id &&\n                m.message &&\n                m.timestamp &&\n                moment(m.timestamp).isValid();\n\n            if (!valid) ++failed;\n\n            return valid;\n        });\n\n        let t = await db.sequelize.transaction();\n\n        try {\n            for (const message of messages) {\n                let new_message = {\n                    channel: message.channel,\n                    user: message.user.replace(/[^\\x00-\\x7F]/g, ''),\n                    discord_id: message.discord_id,\n                    message: message.message.replace(/[^\\x00-\\x7F]/g, ''),\n                    created_at: moment(message.timestamp).format()\n                };\n\n                let hash = crypto\n                    .createHash('sha1')\n                    .update(JSON.stringify(new_message))\n                    .digest('hex');\n\n                new_message.hash = hash;\n\n                try {\n                    await db.discord_chat_messages.create(new_message, {\n                        transaction: t\n                    });\n\n                    ++inserted;\n                } catch (e) {\n                    if (\n                        err.original.code &&\n                        err.original.code === 'ER_DUP_ENTRY'\n                    ) {\n                        ++duplicate;\n                    } else {\n                        ++failed;\n                    }\n                }\n            }\n\n            await t.commit();\n        } catch (e) {\n            await t.rollback();\n        }\n\n        return res.status(200).send({\n            inserted,\n            duplicate,\n            failed\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/api/internal/PistonController.js",
    "content": "module.exports = {\n    async log(req, res) {\n        let { server, server_id, user, user_id, language, source } = req.body;\n\n        if (\n            !server ||\n            !server_id ||\n            !user ||\n            !user_id ||\n            !language ||\n            !source\n        ) {\n            return res.status(400).send();\n        }\n\n        await db.piston_runs.create({\n            server,\n            server_id,\n            user,\n            user_id,\n            language,\n            source\n        });\n\n        return res.status(200).send();\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/api/v1/PistonController.js",
    "content": "const axios = require('axios');\nconst Redis = require('ioredis');\n\nmodule.exports = {\n    async versions(req, res) {\n        res.set('Access-Control-Allow-Origin', '*');\n        res.set('Access-Control-Allow-Headers', '*');\n\n        if (req.method === 'OPTIONS') {\n            return res.status(200).send();\n        }\n\n        let result = await piston.runtimes();\n\n        result = result.map((lang) => {\n            return {\n                name: lang.language,\n                version: lang.version,\n                aliases: lang.aliases\n            };\n        });\n\n        return res.status(200).send(result);\n    },\n\n    async execute(req, res) {\n        res.set('Access-Control-Allow-Origin', '*');\n        res.set('Access-Control-Allow-Headers', '*');\n\n        if (req.method === 'OPTIONS') {\n            return res.status(200).send();\n        }\n\n        const ip = req.headers['x-real-ip'];\n        const authorization = req.headers['authorization'];\n\n        if (!sails.config.piston.unlimited_keys.includes(authorization)) {\n            const redis = new Redis(6379, 'redis');\n\n            let entry = await redis.get(`piston-${ip}`);\n\n            if (entry) {\n                redis.disconnect();\n\n                return res.status(429).send({\n                    message: 'Requests limited to 2 per second'\n                });\n            } else {\n                await redis.set(`piston-${ip}`, 0, 'px', 500);\n            }\n\n            redis.disconnect();\n        }\n\n        let { language, source, args, stdin, version } = req.body;\n\n        let log = null;\n\n        if (req.body.log !== 0) {\n            log = {\n                server: 'Piston API',\n                user: 'Direct Usage'\n            };\n        }\n\n        try {\n            let result = await piston.execute(\n                language,\n                source,\n                args,\n                stdin,\n                version || '*', //default to latest version\n                log\n            );\n\n            return res.status(200).send({\n                ran: result.ran,\n                language: result.language,\n                version: result.version,\n                output: result.output\n                    ? result.output.replace(/\\r/gi, '').slice(0, 65536)\n                    : '',\n                stdout: result.stdout\n                    ? result.stdout.replace(/\\r/gi, '').slice(0, 65536)\n                    : '',\n                stderr: result.stderr\n                    ? result.stderr.replace(/\\r/gi, '').slice(0, 65536)\n                    : ''\n            });\n        } catch (e) {\n            if (e.status_code === 400) {\n                return res.status(400).send({\n                    message: e.message\n                });\n            } else {\n                return res.status(500).send({\n                    message: 'Execution problem'\n                });\n            }\n        }\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/api/v1/UsersController.js",
    "content": "module.exports = {\n    async read_all(req, res) {\n        const { discord_id } = req.query;\n\n        let query = {\n            where: {},\n            attributes: [\n                'user_id',\n                'discord_api',\n                'username',\n                'display_name',\n                'score'\n            ]\n        };\n\n        if (discord_id) {\n            query.where.discord_api = discord_id;\n        }\n\n        let users = await db.users.find_all(query);\n\n        return res.status(200).send(users);\n    },\n\n    async read(req, res) {\n        const user_id = req.params.user_id;\n\n        let user = await db.users.find_one({\n            where: {\n                user_id\n            },\n            attributes: ['user_id', 'username', 'display_name', 'score']\n        });\n\n        if (!user) {\n            return res.status(404).send();\n        }\n\n        return res.status(200).send(user);\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/api/v1/stats/DiscordController.js",
    "content": "const moment = require('moment');\n\nmodule.exports = {\n    async messages(req, res) {\n        let { user, discord_id, term, start, end, limit } = req.query;\n\n        if (!Array.is_array(user) && typeof user !== 'undefined') {\n            user = [user];\n        }\n\n        if (!Array.is_array(discord_id) && typeof discord_id !== 'undefined') {\n            discord_id = [discord_id];\n        }\n\n        let query = {\n            where: {\n                [$and]: []\n            },\n            attributes: [\n                'user',\n                'discord_id',\n                [db.sequelize.literal('count(*)'), 'messages']\n            ],\n            order: [[db.sequelize.col('messages'), 'desc']],\n            group: ['discord_id'],\n            limit: 1000\n        };\n\n        let dates = [];\n\n        if (user) {\n            query.where.user = user;\n        }\n\n        if (discord_id) {\n            query.where.discord_id = discord_id;\n        }\n\n        if (term) {\n            query.where.message = {\n                [$like]: '%' + term + '%'\n            };\n        }\n\n        if (start) {\n            start = moment(start);\n\n            if (start.isValid()) {\n                query.where[$and].push({\n                    created_at: {\n                        [$gte]: start.format('YYYY-MM-DD HH:mm:ss')\n                    }\n                });\n            }\n        }\n\n        if (end) {\n            end = moment(end);\n\n            if (end.isValid()) {\n                query.where[$and].push({\n                    created_at: {\n                        [$lte]: end.format('YYYY-MM-DD HH:mm:ss')\n                    }\n                });\n            }\n        }\n\n        if (limit > 0 && limit <= 1000) {\n            query.limit = +limit;\n        }\n\n        let stats = await db.discord_chat_messages.find_all(query);\n\n        return res.send(stats);\n    },\n\n    async channels(req, res) {\n        let { user, discord_id, start, end, limit } = req.query;\n\n        let query = {\n            where: {\n                [$and]: []\n            },\n            attributes: [\n                'channel',\n                [db.sequelize.literal('count(*)'), 'messages']\n            ],\n            order: [[db.sequelize.col('messages'), 'desc']],\n            group: ['channel'],\n            limit: 1000\n        };\n\n        let dates = [];\n\n        if (user) {\n            query.where.user = {\n                [$like]: '%' + user.replace(/[^\\x00-\\x7F]/g, '') + '%'\n            };\n        }\n\n        if (discord_id) {\n            query.where.discord_id = discord_id;\n        }\n\n        if (start) {\n            start = moment(start);\n\n            if (start.isValid()) {\n                query.where[$and].push({\n                    created_at: {\n                        [$gte]: start.format('YYYY-MM-DD HH:mm:ss')\n                    }\n                });\n            }\n        }\n\n        if (end) {\n            end = moment(end);\n\n            if (end.isValid()) {\n                query.where[$and].push({\n                    created_at: {\n                        [$lte]: end.format('YYYY-MM-DD HH:mm:ss')\n                    }\n                });\n            }\n        }\n\n        if (limit > 0 && limit <= 1000) {\n            query.limit = +limit;\n        }\n\n        let stats = await db.discord_chat_messages.find_all(query);\n\n        return res.status(200).send(stats);\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/api/v1/stats/PistonController.js",
    "content": "const moment = require('moment');\n\nmodule.exports = {\n    async usage(req, res) {\n        let { start, end, category } = req.query;\n\n        let query = {\n            where: {\n                [$and]: []\n            }\n        };\n\n        let where = query.where[$and];\n\n        switch (category) {\n            case 'bot':\n                where.push({\n                    server_id: {\n                        [$ne]: null\n                    }\n                });\n                break;\n            case 'emkc':\n                where.push({\n                    server_id: null\n                });\n                where.push({\n                    server: 'EMKC'\n                });\n                break;\n            case 'direct':\n                where.push({\n                    server_id: null\n                });\n                where.push({\n                    server: 'Piston API'\n                });\n                break;\n        }\n\n        if (start) {\n            start = moment(start);\n\n            if (start.isValid()) {\n                where.push({\n                    created_at: {\n                        [$gte]: start.format('YYYY-MM-DD HH:mm:ss')\n                    }\n                });\n            }\n        }\n\n        if (end) {\n            end = moment(end);\n\n            if (end.isValid()) {\n                where.push({\n                    created_at: {\n                        [$lte]: end.format('YYYY-MM-DD HH:mm:ss')\n                    }\n                });\n            }\n        }\n\n        let count = await db.piston_runs.count(query);\n\n        return res.status(200).send({\n            count\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/controllers/api/v2/PistonController.js",
    "content": "const axios = require('axios');\nconst Redis = require('ioredis');\n\nmodule.exports = {\n    async runtimes(req, res) {\n        res.set('Access-Control-Allow-Origin', '*');\n        res.set('Access-Control-Allow-Headers', '*');\n\n        if (req.method === 'OPTIONS') {\n            return res.status(200).send();\n        }\n\n        let result = await piston.runtimes();\n\n        return res.status(200).send(result);\n    },\n\n    async execute(req, res) {\n        res.set('Access-Control-Allow-Origin', '*');\n        res.set('Access-Control-Allow-Headers', '*');\n\n        if (req.method === 'OPTIONS') {\n            return res.status(200).send();\n        }\n\n        const ip = req.headers['x-real-ip'];\n        const authorization = req.headers['authorization'];\n\n        if (!sails.config.piston.unlimited_keys.includes(authorization)) {\n            const redis = new Redis(6379, 'redis');\n\n            let entry = await redis.get(`piston-${ip}`);\n\n            if (entry) {\n                redis.disconnect();\n\n                return res.status(429).send({\n                    message: 'Requests limited to 1 per 200ms'\n                });\n            } else {\n                await redis.set(`piston-${ip}`, 0, 'px', 200);\n            }\n\n            redis.disconnect();\n        }\n\n        let {\n            language,\n            files,\n            args,\n            stdin,\n            version,\n            run_timeout,\n            compile_timeout,\n            run_memory_limit,\n            compile_memory_limit\n        } = req.body;\n\n        let log = null;\n\n        if (req.body.log !== 0) {\n            log = {\n                server: 'Piston API',\n                user: 'Direct Usage'\n            };\n        }\n\n        try {\n            let result = await piston.execute(\n                language,\n                files,\n                args,\n                stdin,\n                version,\n                log,\n                {\n                    run: run_timeout,\n                    compile: compile_timeout\n                },\n                {\n                    run: run_memory_limit,\n                    compile: compile_memory_limit\n                }\n            );\n\n            return res.status(200).send({\n                language: result.language,\n                version: result.version,\n                run: result.run,\n                compile: result.compile\n            });\n        } catch (e) {\n            if (e.status_code === 400) {\n                return res.status(400).send({\n                    message: e.message\n                });\n            } else {\n                return res.status(500).send({\n                    message: 'Execution problem: ' + e.message\n                });\n            }\n        }\n    }\n};\n"
  },
  {
    "path": "platform/api/policies/api_internal_auth.js",
    "content": "module.exports = (req, res, next) => {\n    let authorization;\n\n    Object.keys(req.headers).for_each((key) => {\n        if (key.to_lower_case() === 'authorization')\n            authorization = req.headers[key];\n    });\n\n    if (authorization !== sails.config.api.internal_key) {\n        return res.send(401, {\n            message: 'Invalid authorization'\n        });\n    }\n\n    return next();\n};\n"
  },
  {
    "path": "platform/api/policies/common.js",
    "content": "module.exports = async (req, res, next) => {\n    req.local = req.local || { user_id: null };\n\n    req.local.constant = constant;\n\n    // get the logged in user\n    let user = await db.users.find_one({\n        where: {\n            user_id: req.session.user_id || null\n        }\n    });\n\n    if (user) {\n        req.local.user_id = user.user_id;\n        req.local.user = user;\n    }\n\n    return next();\n};\n"
  },
  {
    "path": "platform/api/policies/is_admin.js",
    "content": "module.exports = (req, res, next) => {\n    if (!req.local.user || !req.local.user.is_staff) {\n        return res.redirect('/');\n    }\n\n    return next();\n};\n"
  },
  {
    "path": "platform/api/policies/is_prod.js",
    "content": "module.exports = (req, res, next) => {\n    if (!constant.is_prod) {\n        return res.redirect('/');\n    }\n\n    return next();\n};\n"
  },
  {
    "path": "platform/api/policies/logged_in.js",
    "content": "module.exports = (req, res, next) => {\n    if (!req.local.user_id) return res.redirect('/');\n    return next();\n};\n"
  },
  {
    "path": "platform/api/services/api.js",
    "content": "module.exports = {\n    handle_err(res, err) {\n        console.log(err, '\\n\\n');\n\n        try {\n            err = JSON.parse(err.message);\n\n            return res.send({\n                message: err[0] || 'An error occurred',\n                errors: err[1]\n            });\n        } catch (e) {\n            return res.send({\n                message: err.message || 'An error occurred'\n            });\n        }\n    }\n};\n"
  },
  {
    "path": "platform/api/services/constant.js",
    "content": "let constant = {\n    no: 0,\n    yes: 1,\n\n    awards: {\n        type: {\n            contest_first_overall: 1,\n            contest_second_overall: 2,\n            contest_third_overall: 3,\n            contest_first_language: 4,\n            general_participation: 5\n        },\n        ref_type: {\n            contests: 1\n        }\n    },\n\n    challenges: {\n        supported_languages: [\n            'js',\n            'python',\n            'go',\n            'c',\n            'ruby',\n            'cpp',\n            'cs',\n            'php',\n            'swift',\n            'java',\n            'rust',\n            'julia',\n            'bash',\n            'perl',\n            'kotlin',\n            'haskell',\n            'nim'\n        ],\n        difficulty: {\n            easy: 1,\n            medium: 2,\n            hard: 3\n        }\n    },\n\n    contests: {\n        disallowed_languages: [\n            'python2',\n            'awk',\n            'dotnet',\n            'csharp.net',\n            'basic.net'\n        ],\n        golf_languages: ['jelly', 'osabie']\n    },\n\n    channels: {\n        emkc: '483979558249562112', // emkc-felix-piston\n        python: '483980259239264256', // python\n        js: '483977935225749504', // js-ts-node\n        go: '484027805605298197', // other-languages\n        c: '483978202092535809', // c-cpp-csharp\n        ruby: '484027805605298197', // other-languages\n        cpp: '483978202092535809', // c-cpp-csharp\n        cs: '483978202092535809', // c-cpp-csharp\n        php: '484027805605298197', // other-languages\n        swift: '484027805605298197', // other-languages\n        java: '483979599131312128' // java-kotlin\n    },\n\n    roles: {\n        emkc_member: '486562889046556682',\n        emkc_novice: '489975146782785536',\n        emkc_hero: '489975618016903180',\n        emkc_master: '489975728822288384',\n        emkc_legend: '490314890779688963',\n        emkc_winner: '490324386675425281'\n    },\n\n    server_id: '473161189120147456',\n\n    piston: {\n        timeouts: {\n            compile: 10000,\n            run: 3000\n        },\n        memory_limits: {\n            compile: -1,\n            run: -1\n        }\n    },\n\n    set_dynamic() {\n        this.base_url = sails.config.base_url;\n        this.cdn_url = this.base_url + '/cdn';\n        this.is_prod = sails.config.environment === 'production';\n        this.piston_url =\n            sails.config.environment === 'production'\n                ? 'http://' + sails.config.piston.host + '/api/v2'\n                : 'https://emkc.org/api/v2/piston';\n    }\n};\n\nconstant.set_dynamic();\n\nmodule.exports = constant;\n"
  },
  {
    "path": "platform/api/services/contests.js",
    "content": "module.exports = {\n    get_cases(contest, redact = false) {\n        if (contest.input === '' || contest.output === '') {\n            return [];\n        }\n\n        const { inputs, outputs } = test_cases.get_inputs_and_outputs(contest);\n        let cases = [];\n\n        for (let i = 0; i < inputs.length; ++i) {\n            let input = inputs[i];\n\n            let this_case = {\n                hide_input: false,\n                hide_output: false,\n                hide_ignore_active: false,\n                args: input,\n                stdin: input.join('\\n'),\n                output: outputs[i].replace(/\\\\n/g, '\\n')\n            };\n\n            if (input[0].length == 0) {\n                // starts with a pipe\n                //|opt_string|.....\n                this_case.args = input.splice(2);\n                this_case.stdin = this_case.args.join('\\n');\n\n                let opt_string = input[1];\n\n                // e.g. |hide_input,hide_output|hello|world\n                opt_string.split(',').for_each((opt) => {\n                    let vals = opt.split('=');\n                    this_case[vals[0]] = vals.length == 1 || vals[1]; // true if there is no =, else the value after the =\n                });\n            }\n\n            // Hide data from the front-end, but not from the backend\n            if (redact && (contest.active || this_case.hide_ignore_active)) {\n                if (this_case.hide_input) {\n                    this_case.args = this_case.args.map((_) => 'hidden');\n                    this_case.stdin = '[hidden]';\n                }\n                if (this_case.hide_output) {\n                    this_case.output = '[hidden]';\n                }\n            }\n\n            cases.push(this_case);\n        }\n\n        return cases;\n    },\n\n    async validate_submission(test_cases, solution, language, version) {\n        for (const test_case of test_cases) {\n            let test_result = await piston.execute(\n                language,\n                solution,\n                test_case.args,\n                test_case.stdin,\n                version\n            );\n            if (test_result.run.stdout.trim() !== test_case.output.trim()) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n};\n"
  },
  {
    "path": "platform/api/services/discord.js",
    "content": "const request = require('request-promise');\n\nmodule.exports = {\n    async api(method, url, body = null) {\n        const options = {\n            method,\n            url: 'https://discord.com/api/v10' + url,\n            headers: {\n                Authorization: 'Bot ' + sails.config.felix.key\n            },\n            json: true,\n            simple: false,\n            resolveWithFullResponse: true\n        };\n\n        if (body) {\n            options.body = body;\n        }\n\n        const response = await request(options);\n\n        return response;\n    }\n};\n"
  },
  {
    "path": "platform/api/services/dispenserd.js",
    "content": "const request = require('request-promise');\n\nmodule.exports = {\n    lane_main: 'main',\n\n    job_test: 'test',\n\n    /**\n     * dispenserd.schedule(dispenserd.job_test, {\n     *     key: 'value'\n     * });\n     */\n    schedule(job, options) {\n        options.job = job;\n\n        request\n            .post({\n                url:\n                    'http://' + sails.config.dispenserd.host + ':8282/schedule',\n                body: JSON.stringify({\n                    lane: options.lane || dispenserd.lane_main,\n                    priority: options.priority || 10000,\n                    message: JSON.stringify(options)\n                }),\n                resolveWithFullResponse: true,\n                simple: false\n            })\n            .catch((err) => {\n                console.log('job failed to schedule');\n            });\n    }\n};\n"
  },
  {
    "path": "platform/api/services/error.js",
    "content": "const moment = require('moment');\n\nmodule.exports = {\n    log(err, msg) {\n        var final_message = '[msg] ' + msg + '\\n' + '[date] ' + util.now();\n\n        if (err) {\n            final_message += '\\n[err] ' + err.toString();\n        }\n\n        console.log('\\n---\\n' + final_message);\n    }\n};\n"
  },
  {
    "path": "platform/api/services/mailer.js",
    "content": "const moment = require('moment');\nconst q = require('q');\nconst mailgun = require('mailgun-js')({\n    apiKey: sails.config.mailgun.key,\n    domain: sails.config.mailgun.domain\n});\n\nmodule.exports = {\n    send(to, subject, content, template, variables) {\n        var final_content;\n\n        var from = variables.context.name + ' <no-reply@emkc.org>';\n\n        subject = subject.replace('{{name}}', variables.context.name);\n\n        var send = () => {\n            mailgun.messages().send(\n                {\n                    from,\n                    to: constant.email_intercept || to,\n                    'h:Reply-to': variables.reply_to || 'no-reply@emkc.org',\n                    subject,\n                    html: final_content\n                },\n                (err, body) => {\n                    try {\n                        console.log('email to: ' + to);\n                        console.log('subject: ' + subject);\n                        console.log('err: ' + err);\n                        console.log('body: ' + JSON.stringify(body));\n                    } catch (e) {\n                        console.log('in catch');\n                    }\n                }\n            );\n        };\n\n        if (template) {\n            views.render(template, variables).then((template_content) => {\n                final_content = template_content;\n                send();\n            });\n        } else {\n            final_content = content;\n            send();\n        }\n    }\n};\n"
  },
  {
    "path": "platform/api/services/piston.js",
    "content": "const axios = require('axios');\nconst timeout = (ms) => new Promise((res) => set_timeout(res, ms));\n\nconst emkc_internal_log_message = {\n    server: 'EMKC',\n    user: 'EMKC Usage'\n};\n\nclass PistonError extends Error {\n    constructor(message, status_code) {\n        super(status_code + ': ' + message);\n        this.message = message;\n        this.error_message = message;\n        this.status_code = status_code;\n    }\n}\n\nmodule.exports = {\n    languages: {\n        python: 'python',\n        javascript: 'javascript',\n        ruby: 'ruby',\n        go: 'go',\n        c: 'c',\n        cpp: 'cpp',\n        csharp: 'csharp',\n        php: 'php',\n        swift: 'swift',\n        java: 'java'\n    },\n\n    async runtimes() {\n        let result = await axios.get(constant.piston_url + '/runtimes');\n\n        return result.data;\n    },\n\n    async packages() {\n        let result = await axios.get(constant.piston_url + '/packages');\n\n        return result.data;\n    },\n\n    async install(language, version) {\n        let result = await axios.post(\n            constant.piston_url + `/packages/${language}/${version}`\n        );\n\n        return result.data;\n    },\n\n    async uninstall(language, version) {\n        let result = await axios.delete(\n            constant.piston_url + `/packages/${language}/${version}`\n        );\n\n        return result.data;\n    },\n\n    async execute(\n        language,\n        files,\n        args,\n        stdin,\n        version,\n        log_message = emkc_internal_log_message,\n        timeouts = {},\n        memory_limits = {}\n    ) {\n        if (!Array.is_array(args)) {\n            args = [];\n        }\n\n        if (typeof files === 'string') {\n            // Assume this is just source, not files\n            files = [\n                {\n                    content: files\n                }\n            ];\n        }\n\n        await timeout(constant.is_prod ? 0 : 500); // Delay by 0.5 seconds when using the public api\n\n        const compile_timeout = constant.piston.timeouts.compile;\n        const run_timeout = constant.piston.timeouts.run;\n        const compile_memory_limit = constant.piston.memory_limits.compile;\n        const run_memory_limit = constant.piston.memory_limits.run;\n\n        const request_timeouts = {\n            run_timeout,\n            compile_timeout\n        };\n        const request_memory_limits = {\n            run_memory_limit,\n            compile_memory_limit\n        };\n\n        if (timeouts.compile) {\n            request_timeouts.compile_timeout = Math.min(\n                compile_timeout,\n                timeouts.compile\n            );\n        }\n\n        if (timeouts.run) {\n            request_timeouts.run_timeout = Math.min(run_timeout, timeouts.run);\n        }\n\n        if (memory_limits.compile) {\n            request_memory_limits.compile_memory_limit =\n                compile_memory_limit === -1\n                    ? memory_limits.compile\n                    : Math.min(compile_memory_limit, memory_limits.compile);\n        }\n\n        if (memory_limits.run) {\n            request_memory_limits.run_memory_limit =\n                run_memory_limit === -1\n                    ? memory_limits.run\n                    : Math.min(run_memory_limit, memory_limits.run);\n        }\n\n        let result = await axios({\n            method: 'post',\n            url: constant.piston_url + '/execute',\n            data: {\n                language,\n                version,\n                files,\n                args,\n                stdin,\n                ...request_timeouts,\n                ...request_memory_limits\n            }\n        });\n\n        if (result.status !== 200) {\n            throw new PistonError(result.data.message, result.status);\n        }\n\n        if (log_message) {\n            db.piston_runs.create({\n                ...log_message,\n                language,\n                source: files[0].content\n            });\n        }\n\n        let output = '';\n        let stdout = '';\n        let stderr = '';\n        let ran = true;\n\n        if (result.data.compile) {\n            output += result.data.compile.output;\n            stdout += result.data.compile.stdout;\n            stderr += result.data.compile.stderr;\n            ran = ran && result.data.compile.code == 0;\n        }\n\n        if (result.data.run) {\n            output += result.data.run.output;\n            stdout += result.data.run.stdout;\n            stderr += result.data.run.stderr;\n            ran = ran && result.data.run.code == 0;\n        }\n\n        return {\n            ...result.data,\n            output,\n            stdout,\n            stderr,\n            ran\n        };\n    }\n};\n"
  },
  {
    "path": "platform/api/services/test_cases.js",
    "content": "module.exports = {\n    get_inputs_and_outputs(test_object) {\n        const inputs = test_object.input\n            .split('\\n')\n            .map((input) => input.split('|'));\n        const outputs = test_object.output.split('\\n');\n        return { inputs, outputs };\n    },\n\n    are_valid(test_object) {\n        return (\n            test_object.input !== '' &&\n            test_object.output !== '' &&\n            test_object.input.split('\\n').length ===\n                test_object.output.split('\\n').length\n        );\n    }\n};\n"
  },
  {
    "path": "platform/api/services/twig.js",
    "content": "const moment = require('moment');\n\nconst twig = require('twig');\n\ntwig.extendFilter('noscript', (value) => {\n    if (!value) {\n        return value;\n    }\n\n    return value.replace(/\\//gi, '\\\\/');\n});\n\nmodule.exports = {\n    starts_with(string, path) {\n        let pattern = new RegExp('^' + path.replace('/', '\\\\/'));\n\n        return pattern.test(string);\n    }\n};\n"
  },
  {
    "path": "platform/api/services/util.js",
    "content": "const fs = require('fs');\nconst moment = require('moment');\n\nmodule.exports = {\n    now() {\n        return moment().format('YYYY-MM-DD HH:mm:ss');\n    },\n\n    slugify(string) {\n        return (string + '')\n            .toLowerCase()\n            .trim()\n            .replace(/[^a-z0-9 ]+/g, '')\n            .replace(/ +/g, '-')\n            .replace(/^[\\s\\-]+/gi, '')\n            .replace(/[\\s\\-]+$/gi, '');\n    },\n\n    time_diff(start_date, end_date) {\n        var diff = parse_int(end_date.diff(start_date) / 1000);\n\n        var days = diff / 60 / 60 / 24;\n        var hours = diff / 60 / 60;\n        var minutes = diff / 60;\n        var seconds = diff;\n\n        var time, unit;\n\n        for (;;) {\n            if (hours >= 24) {\n                time = Math.round(days);\n                break;\n            }\n            if (minutes >= 60) {\n                time = Math.round(hours);\n                break;\n            }\n            if (seconds >= 60) {\n                time = Math.round(minutes);\n                break;\n            }\n\n            time = seconds >= 0 ? seconds : 0;\n            break;\n        }\n\n        for (;;) {\n            if (hours >= 24) {\n                unit = 'days';\n                break;\n            }\n            if (minutes >= 60) {\n                unit = 'hours';\n                break;\n            }\n            if (seconds >= 60) {\n                unit = 'minutes';\n                break;\n            }\n\n            unit = 'seconds';\n            break;\n        }\n\n        if (unit === 'days' && time > 30) {\n            var months = Math.round(time / 30);\n            if (months === 1) {\n                return '1 month';\n            } else {\n                return months + ' months';\n            }\n        }\n\n        if (time === 1) {\n            return time + ' ' + unit.slice(0, -1);\n        } else {\n            return time + ' ' + unit;\n        }\n    },\n\n    time_ago(the_time) {\n        var start_date = moment(the_time);\n        var end_date = moment();\n\n        return this.time_diff(start_date, end_date);\n    },\n\n    bury_upload(file) {\n        if (!file) return null;\n\n        file.upload({ dirname: '/tmp' }, (err, files) => {\n            files.for_each((file) => {\n                fs.unlink(file.fd);\n            });\n        });\n    }\n};\n"
  },
  {
    "path": "platform/api/services/views.js",
    "content": "const twig = require('twig');\n\nmodule.exports = {\n    async render(template, data) {\n        data.sails = sails;\n        data.constant = constant;\n\n        return await twig\n            .twig({\n                allowInlineIncludes: true,\n                base: root_dir + '/platform/views',\n                path: root_dir + '/platform/views/' + template + '.twig',\n                async: false\n            })\n            .render(data);\n    }\n};\n"
  },
  {
    "path": "platform/config/blueprints.js",
    "content": "module.exports.blueprints = {\n    actions: false,\n    shortcuts: false,\n    rest: false,\n    index: false\n};\n"
  },
  {
    "path": "platform/config/bootstrap.js",
    "content": "process.env.TZ = 'UTC';\n\nrequire('nocamel');\n\nconst path = require('path');\nroot_dir = path.resolve(__dirname + '/../../');\n\nPromise = require('bluebird');\n\nlet axios = require('axios');\naxios.defaults.validateStatus = () => true;\n\nmodule.exports.bootstrap = (cb) => {\n    db = require(root_dir + '/platform/models/index.js');\n\n    sails.local = { root_dir };\n    sails.twig = require(root_dir + '/platform/api/services/twig.js');\n    sails.local.constant = require(root_dir +\n        '/platform/api/services/constant.js');\n    sails.local.epoch = +new Date();\n\n    sails.io.sockets.on('connection', (socket) => {\n        // test for code room socket\n        var hash = /\\/r\\/([a-zA-Z0-9]+)/gi.exec(\n            socket.handshake.headers.referer\n        );\n        hash = hash.length > 1 ? hash[1] : null;\n\n        if (hash) return code_rooms.handle_socket_actions(socket, hash);\n    });\n\n    cb();\n};\n"
  },
  {
    "path": "platform/config/controllers.js",
    "content": "module.exports.controllers = {\n    blueprints: {\n        actions: false,\n        rest: false,\n        shortcuts: false,\n        prefix: '',\n        pluralize: false\n    },\n\n    jsonp: false,\n    expectIntegerId: false\n};\n"
  },
  {
    "path": "platform/config/http.js",
    "content": "module.exports.http = {\n    middleware: {\n        xframe: require('lusca').xframe('SAMEORIGIN'),\n        order: [\n            'startRequestTimer',\n            'xframe',\n            'cookieParser',\n            'session',\n            'bodyParser',\n            'test_json',\n            'compress',\n            'methodOverride',\n            '$custom',\n            'router',\n            'www',\n            'favicon',\n            '404',\n            '500'\n        ],\n        test_json(err, req, res, next) {\n            if (err) {\n                return res.send(400, {\n                    message: 'Invalid JSON received'\n                });\n            }\n\n            return next();\n        }\n    },\n\n    bodyParser() {\n        return require('skipper')({ limit: '4096mb' });\n    }\n};\n"
  },
  {
    "path": "platform/config/local.js.sample",
    "content": "module.exports = {\n\n    port: 2727,\n    environment: 'development',\n    base_url: 'http://127.0.0.1:2005',\n    db: {\n        username: 'root',\n        password: 'root',\n        database: 'emkc',\n        host: 'mysql',\n        dialect: 'mysql',\n        logging: false,\n        timezone: '+00:00',\n        define: {\n            underscored: true,\n            timestamps: false\n        }\n    },\n    api: {\n        internal_key: ''\n    },\n    discord: {\n        client_id: '496807648289882112',\n        client_secret: 'IqJEUGdYR2UxHKrVmVTha__3aLhIC68l'\n    },\n    felix: {\n        key: ''\n    },\n    gcp: {\n        project_id: ''\n    },\n    mailgun: {\n        key: 'yourkeyhere',\n        domain: ''\n    },\n    paypal: {\n        id: '',\n        secret: '',\n        coupon: ''\n    },\n    paypal: {\n        id: '',\n        secret: '',\n        coupon: ''\n    },\n    piston: {\n        host: '127.0.0.1:2000',\n        unlimited_keys: []\n    },\n    dispenserd: {\n        host: '127.0.0.1'\n    },\n    session: {\n        host: 'redis',\n        secret: ''\n    },\n    sockets: {\n        host: 'redis'\n    }\n\n};\n"
  },
  {
    "path": "platform/config/paths.js",
    "content": "module.exports.paths = {\n    public: __dirname + '/../public'\n};\n"
  },
  {
    "path": "platform/config/policies.js",
    "content": "module.exports.policies = {\n    '*': 'common',\n\n    AuthController: {\n        '*': ['common']\n    },\n\n    ChallengesController: {\n        '*': ['common']\n    },\n\n    CommunityController: {\n        '*': ['common'],\n        add_video_request: ['common', 'logged_in'],\n        delete_video_request: ['common', 'logged_in'],\n        video_request_vote: ['common', 'logged_in']\n    },\n\n    ContestsController: {\n        '*': ['common'],\n        submit: ['common', 'logged_in']\n    },\n\n    HomeController: {\n        '*': ['common']\n    },\n\n    MerchController: {\n        '*': ['common']\n    },\n\n    ProfilesController: {\n        '*': ['common']\n    },\n\n    ScriptsController: {\n        '*': ['common']\n    },\n\n    SnippetsController: {\n        '*': ['common'],\n        mine: ['common', 'logged_in'],\n        delete: ['common', 'logged_in'],\n        edit: ['common', 'logged_in']\n    },\n\n    TagsController: {\n        '*': ['common']\n    },\n\n    'admin/ContestsController': {\n        '*': ['common', 'logged_in', 'is_admin']\n    },\n\n    'admin/ChallengesController': {\n        '*': ['common', 'logged_in', 'is_admin']\n    },\n\n    'admin/DashboardController': {\n        '*': ['common', 'logged_in', 'is_admin']\n    },\n\n    'admin/UsersController': {\n        '*': ['common', 'logged_in', 'is_admin']\n    },\n\n    'admin/PistonController': {\n        '*': ['common', 'logged_in', 'is_admin', 'is_prod']\n    },\n\n    'api/internal/ChatsController': {\n        '*': ['common', 'api_internal_auth']\n    },\n\n    'api/internal/PistonController': {\n        '*': ['common', 'api_internal_auth']\n    },\n\n    'api/v1/PistonController': {\n        '*': ['common']\n    },\n\n    'api/v1/UsersController': {\n        '*': ['common']\n    },\n\n    'api/v1/stats/DiscordController': {\n        '*': ['common']\n    },\n\n    'api/v1/stats/PistonController': {\n        '*': ['common']\n    }\n};\n"
  },
  {
    "path": "platform/config/routes.js",
    "content": "module.exports.routes = {\n    'GET /': 'HomeController.home',\n    'GET /logout': 'HomeController.logout',\n    'GET /logout_as': 'HomeController.logout_as',\n    'GET /auth/discord': 'AuthController.discord',\n    'GET /auth/discord_cb': 'AuthController.discord_cb',\n    'GET /privacy': 'HomeController.privacy',\n    //'GET /stickers': 'MerchController.stickers',\n    //'POST /stickers/order': 'MerchController.order_stickers',\n    //'GET /stickers/check_code/:code': 'MerchController.check_code',\n\n    'GET /community': 'CommunityController.home',\n    'GET /community/about': 'CommunityController.about',\n    'GET /community/power': 'CommunityController.power',\n\n    'GET /challenges': 'ChallengesController.home',\n    'GET /challenges/choose_language/:challenge_id':\n        'ChallengesController.choose_language',\n    'POST /challenges/execute/:challenge_id': 'ChallengesController.execute',\n    'GET /challenges/:challenge_id/:language': 'ChallengesController.challenge',\n\n    'GET /contests': 'ContestsController.home',\n    'POST /contests/submit': 'ContestsController.submit',\n    'GET /contests/disallowed_languages/:contest_id':\n        'ContestsController.disallowed_languages',\n    'GET /contests/:contest_id/:slug': 'ContestsController.contest',\n\n    'GET /snippets': 'SnippetsController.create',\n    'POST /snippets': 'SnippetsController.create',\n    'GET /snippets/mine': 'SnippetsController.mine',\n    'GET /s/:hash': 'SnippetsController.view',\n    'GET /s/:hash/raw': 'SnippetsController.view',\n    'POST /snippets/delete/:hash': 'SnippetsController.delete',\n    'GET /snippets/edit/:hash': 'SnippetsController.edit',\n    'POST /snippets/edit/:hash': 'SnippetsController.edit',\n\n    'GET /scripts': 'ScriptsController.home',\n    'GET /scripts/:cli_script_id/:slug': 'ScriptsController.view',\n    'GET /exec/:cli_script_id': 'ScriptsController.exec',\n\n    'GET /@:username': 'ProfilesController.view',\n    'GET /@:username/challenges/:challenge_id/:language':\n        'ChallengesController.view_other',\n\n    // admin\n    'GET /admin': 'admin/DashboardController.dashboard',\n    'GET /admin/contests': 'admin/ContestsController.view_all',\n    'GET /admin/challenges': 'admin/ChallengesController.view_all',\n    'GET /admin/challenges/update/:challenge_id':\n        'admin/ChallengesController.update',\n    'POST /admin/challenges/update/:challenge_id':\n        'admin/ChallengesController.update',\n    'GET /admin/challenges/create': 'admin/ChallengesController.create',\n    'POST /admin/challenges/create': 'admin/ChallengesController.create',\n    'GET /admin/contests/all': 'admin/ContestsController.view_all',\n    'GET /admin/contests/create': 'admin/ContestsController.create',\n    'POST /admin/contests/create': 'admin/ContestsController.create',\n    'GET /admin/contests/update/:contest_id': 'admin/ContestsController.update',\n    'POST /admin/contests/update/:contest_id':\n        'admin/ContestsController.update',\n    'POST /admin/submissions/validate/:contest_id':\n        'admin/ContestsController.validate_submissions',\n    'POST /admin/submissions/delete':\n        'admin/ContestsController.delete_submission',\n    'GET /admin/users': 'admin/UsersController.view_all',\n    'GET /admin/users/login_as': 'admin/UsersController.login_as',\n    'GET /admin/piston': 'admin/PistonController.view_all',\n    'GET /admin/piston/packages': 'admin/PistonController.packages',\n    'GET /admin/piston/install': 'admin/PistonController.install',\n    'GET /admin/piston/uninstall': 'admin/PistonController.uninstall',\n\n    // service api\n    'GET /api/internal/chats/last': 'api/internal/ChatsController.last',\n    'POST /api/internal/chats': 'api/internal/ChatsController.create',\n    'POST /api/internal/piston/log': 'api/internal/PistonController.log',\n\n    // public api endpoints\n    'GET /api/v1/stats/discord/messages':\n        'api/v1/stats/DiscordController.messages',\n    'GET /api/v1/stats/discord/channels':\n        'api/v1/stats/DiscordController.channels',\n    'GET /api/v1/stats/piston/usage': 'api/v1/stats/PistonController.usage',\n    'GET /api/v1/users': 'api/v1/UsersController.read_all',\n    'GET /api/v1/users/:user_id': 'api/v1/UsersController.read',\n    'GET /api/v1/piston/versions': 'api/v1/PistonController.versions',\n    'OPTIONS /api/v1/piston/versions': 'api/v1/PistonController.versions',\n    'POST /api/v1/piston/execute': 'api/v1/PistonController.execute',\n    'OPTIONS /api/v1/piston/execute': 'api/v1/PistonController.execute',\n    'GET /api/v2/piston/runtimes': 'api/v2/PistonController.runtimes',\n    'OPTIONS /api/v2/piston/runtimes': 'api/v2/PistonController.runtimes',\n    'POST /api/v2/piston/execute': 'api/v2/PistonController.execute',\n    'OPTIONS /api/v2/piston/execute': 'api/v2/PistonController.execute',\n\n    // catch all (404)\n    'ALL r|^/(?!cdn|css|images|js|lib|other|robots.txt|google*)|':\n        'HomeController.fourohfour'\n};\n"
  },
  {
    "path": "platform/config/session.js",
    "content": "module.exports.session = {\n    adapter: 'redis',\n    key: 'engineerman.sid',\n    cookie: {\n        maxAge: 60 * 60 * 24 * 20 * 1000\n    }\n};\n"
  },
  {
    "path": "platform/config/sockets.js",
    "content": "module.exports.sockets = {\n    adapter: 'socket.io-redis'\n    // transports: ['websocket']\n};\n"
  },
  {
    "path": "platform/config/views.js",
    "content": "const twig = require('twig');\n\nfor (let filter of require('../resources/twig/filters')) {\n    twig.extendFilter(filter.name, filter.filter);\n}\n\nmodule.exports.views = {\n    layout: false,\n    engine: {\n        ext: 'twig',\n        fn: twig.__express\n    }\n};\n"
  },
  {
    "path": "platform/console/common.js",
    "content": "process.env.TZ = 'UTC';\nprocess.setMaxListeners(0);\n\nrequire('nocamel');\n\nPromise = require('bluebird');\n\nroot_dir = require('path').resolve(__dirname + '/../../');\n\nsails = {\n    config: require('../config/local.js')\n};\n\nconstant = require('../api/services/constant.js');\ndiscord = require('../api/services/discord.js');\ndispenserd = require('../api/services/dispenserd.js');\ntwig = require('../api/services/twig.js');\nutil = require('../api/services/util.js');\nviews = require('../api/services/views.js');\ndb = require('../models/index.js');\n"
  },
  {
    "path": "platform/console/cron.js",
    "content": "#!/usr/bin/env node\nrequire('./common');\n\nconst axios = require('axios');\nconst moment = require('moment');\n\nconst timeout = (ms) => new Promise((res) => set_timeout(res, ms));\n\nconst cron = {\n    async calculate_score() {\n        let users = await db.users.find_all();\n\n        for (const user of users) {\n            let total_score = 0;\n\n            // process points from challenges\n            let challenges = await db.user_challenges.find_all({\n                where: {\n                    user_id: user.user_id\n                },\n                include: [\n                    {\n                        model: db.challenges,\n                        as: 'challenge'\n                    }\n                ]\n            });\n\n            let challenges_score = challenges.reduce(\n                (i, c) => i + c.challenge.points,\n                0\n            );\n\n            total_score += challenges_score;\n\n            // process points from awards\n            let awards = await db.awards.find_all({\n                where: {\n                    user_id: user.user_id\n                }\n            });\n\n            let awards_score = awards.reduce((i, a) => i + a.points, 0);\n\n            total_score += awards_score;\n\n            // sync score and apply to discord as appropriate\n            user.score = total_score;\n\n            if (!user.discord_api) {\n                return await user.save();\n            }\n\n            // test for and assign novice role\n            if (user.discord_rank === null && user.score >= 40) {\n                try {\n                    await discord.api(\n                        'put',\n                        `/guilds/473161189120147456/members/${user.discord_api}` +\n                            `/roles/${constant.roles.emkc_novice}`\n                    );\n                    user.discord_rank = 1;\n                } catch (e) {}\n\n                await timeout(1000);\n            }\n\n            // test for and assign hero role\n            if (user.discord_rank === 1 && user.score >= 300) {\n                try {\n                    await discord.api(\n                        'put',\n                        `/guilds/473161189120147456/members/${user.discord_api}` +\n                            `/roles/${constant.roles.emkc_hero}`\n                    );\n                    user.discord_rank = 2;\n                } catch (e) {}\n\n                await timeout(1000);\n            }\n\n            // test for and assign master role\n            if (user.discord_rank === 2 && user.score >= 1000) {\n                try {\n                    await discord.api(\n                        'put',\n                        `/guilds/473161189120147456/members/${user.discord_api}` +\n                            `/roles/${constant.roles.emkc_master}`\n                    );\n                    user.discord_rank = 3;\n                } catch (e) {}\n\n                await timeout(1000);\n            }\n\n            // test for and assign legend role\n            if (user.discord_rank === 3 && user.score >= 5000) {\n                try {\n                    await discord.api(\n                        'put',\n                        `/guilds/473161189120147456/members/${user.discord_api}` +\n                            `/roles/${constant.roles.emkc_legend}`\n                    );\n                    user.discord_rank = 4;\n                } catch (e) {}\n\n                await timeout(1000);\n            }\n\n            await user.save();\n        }\n    },\n\n    async process_awards() {\n        await db.awards.destroy({\n            where: {}\n        });\n\n        // process contest related awards\n        let contests = await db.contests.find_all({\n            where: {\n                end_date: {\n                    [$lt]: util.now()\n                },\n                contest_id: {\n                    [$not_in]: [30]\n                }\n            },\n            include: [\n                {\n                    model: db.contest_submissions,\n                    as: 'submissions',\n                    where: {\n                        late: constant.no\n                    },\n                    include: [\n                        {\n                            model: db.users,\n                            as: 'user'\n                        }\n                    ]\n                }\n            ],\n            order: [\n                [\n                    { model: db.contest_submissions, as: 'submissions' },\n                    'length'\n                ],\n                [\n                    { model: db.contest_submissions, as: 'submissions' },\n                    'created_at'\n                ]\n            ]\n        });\n\n        for (const contest of contests) {\n            // handle 1st-3rd place\n            let placed = [\n                ...new Set(contest.submissions.map((s) => s.user_id))\n            ].slice(0, 3);\n\n            let i = 1;\n\n            for (const user_id of placed) {\n                let type = {\n                    1: constant.awards.type.contest_first_overall,\n                    2: constant.awards.type.contest_second_overall,\n                    3: constant.awards.type.contest_third_overall\n                }[i];\n\n                await db.awards.create({\n                    type,\n                    user_id,\n                    ref_type: constant.awards.ref_type.contests,\n                    ref_id: contest.contest_id,\n                    points: {\n                        [constant.awards.type.contest_first_overall]: 500,\n                        [constant.awards.type.contest_second_overall]: 200,\n                        [constant.awards.type.contest_third_overall]: 75\n                    }[type]\n                });\n\n                ++i;\n            }\n\n            // handle per language\n            let languages = [];\n\n            for (const submission of contest.submissions) {\n                if (languages.includes(submission.language)) {\n                    continue;\n                }\n\n                await db.awards.create({\n                    type: constant.awards.type.contest_first_language,\n                    user_id: submission.user_id,\n                    ref_type: constant.awards.ref_type.contests,\n                    ref_id: contest.contest_id,\n                    points: 50\n                });\n\n                languages.push(submission.language);\n            }\n\n            // handle participation\n            let participants = [\n                ...new Set(contest.submissions.map((s) => s.user_id))\n            ];\n\n            for (const user_id of participants) {\n                await db.awards.create({\n                    type: constant.awards.type.general_participation,\n                    user_id,\n                    ref_type: constant.awards.ref_type.contests,\n                    ref_id: contest.contest_id,\n                    points: 50\n                });\n            }\n        }\n    },\n\n    async update_staff() {\n        await db.users.update(\n            {\n                is_staff: 0\n            },\n            {\n                where: {}\n            }\n        );\n\n        let users = [];\n        let last_id = null;\n\n        let base_url = `/guilds/${constant.server_id}/members?limit=1000`;\n\n        while (true) {\n            let result = await discord.api(\n                'get',\n                base_url + (last_id ? '&after=' + last_id : '')\n            );\n\n            if (result.body.length === 0) {\n                break;\n            }\n\n            users = users.concat(result.body);\n\n            last_id = users.slice(-1)[0].user.id;\n\n            await timeout(1200);\n        }\n\n        users = users\n            .filter((user) => {\n                return user.roles.includes('473167481624854541');\n            })\n            .map((user) => user.user.id);\n\n        await db.users.update(\n            {\n                is_staff: 1\n            },\n            {\n                where: {\n                    discord_api: {\n                        [$in]: users\n                    }\n                }\n            }\n        );\n    },\n\n    async repair_roles() {\n        const update_role = async (user, role) => {\n            console.log('assigning ' + user.username + ' ' + role);\n\n            let res = await discord.api(\n                'put',\n                '/guilds/' +\n                    constant.server_id +\n                    '/members/' +\n                    user.discord_api +\n                    '/roles/' +\n                    role\n            );\n\n            if (res.statusCode === 429) {\n                let retry_after = res.body.retry_after;\n\n                console.log('rate limited, waiting: ' + retry_after);\n\n                await timeout(retry_after);\n                await update_role(user, role);\n            }\n        };\n\n        let users = await db.users.find_all();\n\n        for (const user of users) {\n            // member role\n            if (user.discord_api) {\n                await update_role(user, constant.roles.emkc_member);\n            }\n\n            // novice role\n            if (user.discord_api && user.discord_rank === 1) {\n                await update_role(user, constant.roles.emkc_novice);\n            }\n\n            // hero role\n            if (user.discord_api && user.discord_rank === 2) {\n                await update_role(user, constant.roles.emkc_hero);\n            }\n\n            // master role\n            if (user.discord_api && user.discord_rank === 3) {\n                await update_role(user, constant.roles.emkc_master);\n            }\n\n            // legend role\n            if (user.discord_api && user.discord_rank === 4) {\n                await update_role(user, constant.roles.emkc_legend);\n            }\n        }\n    },\n\n    async contest_status() {\n        let contest = await db.contests.find_one({\n            where: {\n                start_date: {\n                    [$lte]: util.now()\n                },\n                end_date: {\n                    [$gte]: util.now()\n                }\n            },\n            include: [\n                {\n                    model: db.contest_submissions,\n                    as: 'submissions',\n                    include: [\n                        {\n                            model: db.users,\n                            as: 'user'\n                        }\n                    ]\n                }\n            ],\n            order: [\n                ['contest_id', 'desc'],\n                [\n                    { model: db.contest_submissions, as: 'submissions' },\n                    'length'\n                ],\n                [\n                    { model: db.contest_submissions, as: 'submissions' },\n                    'created_at'\n                ]\n            ]\n        });\n\n        if (!contest || contest.submissions.length === 0) {\n            return;\n        }\n\n        let submission = contest.submissions[0];\n\n        discord\n            .api('post', `/channels/${constant.channels.emkc}/messages`, {\n                embeds: [\n                    {\n                        //title: contest.name,\n                        description:\n                            'This contest is active right now. Submit your solution soon and ' +\n                            'try to beat the best solution! ' +\n                            `[Click here](${constant.base_url}${contest.url}) to give it a try.`,\n                        type: 'rich',\n                        color: 0x84e47f,\n                        url: `${constant.base_url}${contest.url}`,\n                        thumbnail: {\n                            url: constant.cdn_url + submission.user.avatar_url\n                        },\n                        fields: [\n                            {\n                                name: '**leader**',\n                                value: submission.user.display_name,\n                                inline: true\n                            },\n                            {\n                                name: '**language used**',\n                                value: submission.language,\n                                inline: true\n                            },\n                            {\n                                name: '**length**',\n                                value: submission.length,\n                                inline: true\n                            }\n                        ],\n                        author: {\n                            name: 'Contest Status: ' + contest.name,\n                            icon_url:\n                                'https://emkc.org/images/icon_circle_64.png'\n                        },\n                        footer: {\n                            text: `There's still ${contest.time_left}left to submit a solution`\n                        }\n                    }\n                ]\n            })\n            .catch((err) => {});\n    }\n};\n\nvar method = process.argv[2].replace(/-/gi, '_').replace(/^_+/gi, '');\n\ncron[method]();\n"
  },
  {
    "path": "platform/console/util.js",
    "content": "#!/usr/bin/env node\nrequire('./common');\n\nconst moment = require('moment');\nconst request = require('request-promise');\n\nlet cron = {\n    ingest_chats() {\n        let messages = require('fs')\n            .read_file_sync('chats.log')\n            .to_string()\n            .split('\\n')\n            .map((msg) => {\n                const pieces = msg.split('|');\n\n                const [timestamp, channel, user] = pieces;\n                const message = pieces.slice(3).join('');\n\n                return {\n                    timestamp,\n                    channel,\n                    user,\n                    message\n                };\n            });\n\n        request({\n            method: 'post',\n            url: 'http://127.0.0.1:2727/api/internal/chats',\n            headers: {\n                authorization: sails.config.api.internal_key\n            },\n            body: messages,\n            json: true,\n            simple: true\n        });\n    }\n};\n\nlet method = process.argv[2].replace(/-/gi, '_').replace(/^_+/gi, '');\n\ncron[method]();\n"
  },
  {
    "path": "platform/emkc.js",
    "content": "/**\n * Engineer Man Knowledge Center\n * Copyright (C) 2021 Brian Seymour and EMKC Contributors\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n **/\n\nrequire('sails').lift(require('optimist').argv);\n"
  },
  {
    "path": "platform/migrations/config.json.sample",
    "content": "{\n  \"host\": \"mysql\",\n  \"port\": 3306,\n  \"user\": \"root\",\n  \"pass\": \"root\",\n  \"db\": \"emkc\",\n  \"platform\": \"mysql\"\n}\n"
  },
  {
    "path": "platform/migrations/migrations/20180320123747-initial.sql",
    "content": "up:\ncreate table users (\n    user_id int unsigned not null auto_increment,\n    is_staff tinyint unsigned not null default 0,\n    username varchar(64) null,\n    email varchar(128) null,\n    password varchar(40) null,\n    discord_api varchar(32) null,\n    avatar_url varchar(128) null,\n    score int not null default 0,\n    created_at datetime not null,\n    primary key (user_id),\n    key is_staff (is_staff),\n    key username (username),\n    key email (email),\n    key discord_api (discord_api),\n    key score (score)\n)engine=innodb default charset=utf8;\n\ncreate table questions (\n    question_id int unsigned not null auto_increment,\n    user_id int unsigned not null,\n    title varchar(128) not null,\n    question mediumtext not null,\n    score int not null default 0,\n    comments int unsigned not null default 0,\n    created_at datetime not null,\n    primary key (question_id),\n    key user_id (user_id),\n    key score (score),\n    key comments (comments),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ncreate table snippets (\n    snippet_id int unsigned not null auto_increment,\n    user_id int unsigned null,\n    hash varchar(40) not null,\n    snip mediumtext not null,\n    created_at datetime not null,\n    primary key (snippet_id),\n    key user_id (user_id),\n    key hash (hash),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ncreate table comments (\n    comment_id int unsigned not null auto_increment,\n    question_id int unsigned not null,\n    base_id int unsigned null,\n    parent_id int unsigned null,\n    user_id int unsigned not null,\n    comment mediumtext not null,\n    depth int not null default 0,\n    score int not null default 0,\n    created_at datetime not null,\n    primary key (comment_id),\n    key question_id (question_id),\n    key base_id (base_id),\n    key parent_id (parent_id),\n    key user_id (user_id),\n    key depth (depth),\n    key score (score),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ncreate table question_votes (\n    question_vote_id int unsigned not null auto_increment,\n    question_id int unsigned not null,\n    user_id int unsigned not null,\n    value tinyint not null,\n    primary key (question_vote_id),\n    key question_id (question_id),\n    key user_id (user_id),\n    key value (value)\n)engine=innodb default charset=utf8;\n\ncreate table comment_votes (\n    comment_vote_id int unsigned not null auto_increment,\n    comment_id int unsigned not null,\n    user_id int unsigned not null,\n    value tinyint not null,\n    primary key (comment_vote_id),\n    key comment_id (comment_id),\n    key user_id (user_id),\n    key value (value)\n)engine=innodb default charset=utf8;\n\ncreate table tags (\n    tag_id int unsigned not null auto_increment,\n    name varchar(128) not null,\n    primary key (tag_id),\n    key name (name)\n)engine=innodb default charset=utf8;\n\ninsert into tags values (default, 'abend');\ninsert into tags values (default, 'absolute-address');\ninsert into tags values (default, 'absolute-coding');\ninsert into tags values (default, 'access-violation');\ninsert into tags values (default, 'acm');\ninsert into tags values (default, 'action-statement');\ninsert into tags values (default, 'actionscript');\ninsert into tags values (default, 'activex');\ninsert into tags values (default, 'ada');\ninsert into tags values (default, 'add');\ninsert into tags values (default, 'ado');\ninsert into tags values (default, 'advanced-scsi-programming-interface');\ninsert into tags values (default, 'aggregation');\ninsert into tags values (default, 'agile-development-methods');\ninsert into tags values (default, 'agile-manifesto');\ninsert into tags values (default, 'alert');\ninsert into tags values (default, 'algol');\ninsert into tags values (default, 'algorithm');\ninsert into tags values (default, 'altair-basic');\ninsert into tags values (default, 'ambient-occlusion');\ninsert into tags values (default, 'aop');\ninsert into tags values (default, 'api');\ninsert into tags values (default, 'applet');\ninsert into tags values (default, 'argument');\ninsert into tags values (default, 'arithmetic-operator');\ninsert into tags values (default, 'array');\ninsert into tags values (default, 'array-of-pointers');\ninsert into tags values (default, 'ascii');\ninsert into tags values (default, 'asp');\ninsert into tags values (default, 'aspi');\ninsert into tags values (default, 'assembler');\ninsert into tags values (default, 'assembly');\ninsert into tags values (default, 'associative-operation');\ninsert into tags values (default, 'autohotkey');\ninsert into tags values (default, 'automata-based-programming');\ninsert into tags values (default, 'automated-unit-testing');\ninsert into tags values (default, 'automation');\ninsert into tags values (default, 'booleanbabel');\ninsert into tags values (default, 'backend');\ninsert into tags values (default, 'back-face-culling');\ninsert into tags values (default, 'background-thread');\ninsert into tags values (default, 'backpropagation-neural-network');\ninsert into tags values (default, 'base-address');\ninsert into tags values (default, 'batch-file');\ninsert into tags values (default, 'batch-job');\ninsert into tags values (default, 'bcpl');\ninsert into tags values (default, 'bean');\ninsert into tags values (default, 'beanshell');\ninsert into tags values (default, 'binary-search');\ninsert into tags values (default, 'bind');\ninsert into tags values (default, 'bit-shift');\ninsert into tags values (default, 'bitwise-operators');\ninsert into tags values (default, 'block');\ninsert into tags values (default, 'block-level-element');\ninsert into tags values (default, 'bom');\ninsert into tags values (default, 'bool');\ninsert into tags values (default, 'boolean');\ninsert into tags values (default, 'boolean-data-type');\ninsert into tags values (default, 'bracket');\ninsert into tags values (default, 'branch');\ninsert into tags values (default, 'brooks');\ninsert into tags values (default, 'bug');\ninsert into tags values (default, 'bug-tracking');\ninsert into tags values (default, 'bugfairy');\ninsert into tags values (default, 'build-computer');\ninsert into tags values (default, 'bytecode');\ninsert into tags values (default, 'compiled-programming-languagec');\ninsert into tags values (default, 'c-sharp');\ninsert into tags values (default, 'c++');\ninsert into tags values (default, 'c#');\ninsert into tags values (default, 'camel-book');\ninsert into tags values (default, 'camelcase');\ninsert into tags values (default, 'captured-variable');\ninsert into tags values (default, 'cc');\ninsert into tags values (default, 'chaos-model');\ninsert into tags values (default, 'char');\ninsert into tags values (default, 'character-code');\ninsert into tags values (default, 'character-encoding');\ninsert into tags values (default, 'character-set');\ninsert into tags values (default, 'chaos-model');\ninsert into tags values (default, 'circuit-satisfiability-problem');\ninsert into tags values (default, 'class');\ninsert into tags values (default, 'class');\ninsert into tags values (default, 'classpath');\ninsert into tags values (default, 'clojure');\ninsert into tags values (default, 'clos');\ninsert into tags values (default, 'closure');\ninsert into tags values (default, 'clr');\ninsert into tags values (default, 'cobol');\ninsert into tags values (default, 'cocoa');\ninsert into tags values (default, 'cocoa-touch');\ninsert into tags values (default, 'code');\ninsert into tags values (default, 'code-refactoring');\ninsert into tags values (default, 'codepage');\ninsert into tags values (default, 'coffeescript');\ninsert into tags values (default, 'command-language');\ninsert into tags values (default, 'comment');\ninsert into tags values (default, 'common-business-oriented-language');\ninsert into tags values (default, 'common-gateway-interface');\ninsert into tags values (default, 'compilation');\ninsert into tags values (default, 'compile');\ninsert into tags values (default, 'compiler');\ninsert into tags values (default, 'complementarity');\ninsert into tags values (default, 'compute');\ninsert into tags values (default, 'computer-science');\ninsert into tags values (default, 'commutative-operation');\ninsert into tags values (default, 'concat');\ninsert into tags values (default, 'concatenation');\ninsert into tags values (default, 'concurrency');\ninsert into tags values (default, 'conditional-expression');\ninsert into tags values (default, 'conditional-statement');\ninsert into tags values (default, 'constant');\ninsert into tags values (default, 'constructor');\ninsert into tags values (default, 'constructor-chaining');\ninsert into tags values (default, 'content-migration');\ninsert into tags values (default, 'control-flow');\ninsert into tags values (default, 'cpan');\ninsert into tags values (default, 'cpl');\ninsert into tags values (default, 'crapplet');\ninsert into tags values (default, 'cs');\ninsert into tags values (default, 'csat');\ninsert into tags values (default, 'css');\ninsert into tags values (default, 'css-compressor');\ninsert into tags values (default, 'css-editor');\ninsert into tags values (default, 'curly-bracket');\ninsert into tags values (default, 'curry');\ninsert into tags values (default, 'cvs');\ninsert into tags values (default, 'cygwin');\ninsert into tags values (default, 'sparse-matrixd');\ninsert into tags values (default, 'darkbasic');\ninsert into tags values (default, 'dart');\ninsert into tags values (default, 'dataflow-programming');\ninsert into tags values (default, 'data-flow-analysis');\ninsert into tags values (default, 'data-flow-diagram');\ninsert into tags values (default, 'data-source');\ninsert into tags values (default, 'data-type');\ninsert into tags values (default, 'datalog');\ninsert into tags values (default, 'dde');\ninsert into tags values (default, 'dead-code');\ninsert into tags values (default, 'debug');\ninsert into tags values (default, 'debugger');\ninsert into tags values (default, 'debugging');\ninsert into tags values (default, 'declaration');\ninsert into tags values (default, 'declarative-programming');\ninsert into tags values (default, 'declare');\ninsert into tags values (default, 'decompiler');\ninsert into tags values (default, 'decrement');\ninsert into tags values (default, 'deductive-database');\ninsert into tags values (default, 'dense-matrix');\ninsert into tags values (default, 'dereference-operator');\ninsert into tags values (default, 'dependent-variable');\ninsert into tags values (default, 'developer');\ninsert into tags values (default, 'dhtml');\ninsert into tags values (default, 'die');\ninsert into tags values (default, 'diff');\ninsert into tags values (default, 'direct-address');\ninsert into tags values (default, 'discrete-optimization');\ninsert into tags values (default, 'dissembler');\ninsert into tags values (default, 'div');\ninsert into tags values (default, 'django');\ninsert into tags values (default, 'dml');\ninsert into tags values (default, 'do');\ninsert into tags values (default, 'dom');\ninsert into tags values (default, 'dragon-book');\ninsert into tags values (default, 'dribbleware');\ninsert into tags values (default, 'dump');\ninsert into tags values (default, 'dword');\ninsert into tags values (default, 'dylan-programming-language');\ninsert into tags values (default, 'dynamic-dump');\ninsert into tags values (default, 'exececlipse');\ninsert into tags values (default, 'ecmascript');\ninsert into tags values (default, 'eight-queens-problem');\ninsert into tags values (default, 'element');\ninsert into tags values (default, 'ellipsis');\ninsert into tags values (default, 'else');\ninsert into tags values (default, 'else-if');\ninsert into tags values (default, 'elsif');\ninsert into tags values (default, 'embedded-java');\ninsert into tags values (default, 'encapsulation');\ninsert into tags values (default, 'encode');\ninsert into tags values (default, 'endian');\ninsert into tags values (default, 'endless-loop');\ninsert into tags values (default, 'eof');\ninsert into tags values (default, 'epoch');\ninsert into tags values (default, 'eq');\ninsert into tags values (default, 'equal');\ninsert into tags values (default, 'error');\ninsert into tags values (default, 'errorlevel');\ninsert into tags values (default, 'esac');\ninsert into tags values (default, 'escape');\ninsert into tags values (default, 'escape-character');\ninsert into tags values (default, 'escape-sequence');\ninsert into tags values (default, 'eval');\ninsert into tags values (default, 'event');\ninsert into tags values (default, 'event-handler');\ninsert into tags values (default, 'event-listener');\ninsert into tags values (default, 'event-driven-programming');\ninsert into tags values (default, 'exec');\ninsert into tags values (default, 'exception');\ninsert into tags values (default, 'exception-handling');\ninsert into tags values (default, 'exists');\ninsert into tags values (default, 'exponent');\ninsert into tags values (default, 'exponential-backoff');\ninsert into tags values (default, 'expression');\ninsert into tags values (default, 'foreachf-programming-language');\ninsert into tags values (default, 'f#');\ninsert into tags values (default, 'false');\ninsert into tags values (default, 'fifth-generation-language');\ninsert into tags values (default, 'first-generation-language');\ninsert into tags values (default, 'first-class-object');\ninsert into tags values (default, 'flag');\ninsert into tags values (default, 'flat-file');\ninsert into tags values (default, 'floating-point');\ninsert into tags values (default, 'for');\ninsert into tags values (default, 'foreach');\ninsert into tags values (default, 'forth');\ninsert into tags values (default, 'forth-generation-language');\ninsert into tags values (default, 'fortran');\ninsert into tags values (default, 'framework');\ninsert into tags values (default, 'front-end');\ninsert into tags values (default, 'full-stack-developer');\ninsert into tags values (default, 'function');\ninsert into tags values (default, 'functional-programming');\ninsert into tags values (default, 'fuzz-testing');\ninsert into tags values (default, 'game-of-lifegame-of-life');\ninsert into tags values (default, 'gang-of-four');\ninsert into tags values (default, 'garbage-collection');\ninsert into tags values (default, 'gaussian-pyramid');\ninsert into tags values (default, 'gcc');\ninsert into tags values (default, 'ge');\ninsert into tags values (default, 'general-purpose-language');\ninsert into tags values (default, 'generation-language');\ninsert into tags values (default, 'genetic-programming');\ninsert into tags values (default, 'gigo');\ninsert into tags values (default, 'github');\ninsert into tags values (default, 'glitch');\ninsert into tags values (default, 'glob');\ninsert into tags values (default, 'glue-code');\ninsert into tags values (default, 'go-language');\ninsert into tags values (default, 'goto');\ninsert into tags values (default, 'gpl');\ninsert into tags values (default, 'grasshopper');\ninsert into tags values (default, 'gt');\ninsert into tags values (default, 'gtk');\ninsert into tags values (default, 'gw-basic');\ninsert into tags values (default, 'haskell-programming-languagehal');\ninsert into tags values (default, 'hard-code');\ninsert into tags values (default, 'hash');\ninsert into tags values (default, 'haskell');\ninsert into tags values (default, 'heap');\ninsert into tags values (default, 'hello-world');\ninsert into tags values (default, 'heuristic-evaluation');\ninsert into tags values (default, 'hex-editor');\ninsert into tags values (default, 'hdml');\ninsert into tags values (default, 'hiew');\ninsert into tags values (default, 'high-level-language');\ninsert into tags values (default, 'html');\ninsert into tags values (default, 'hungarian-notation');\ninsert into tags values (default, 'hwclock');\ninsert into tags values (default, 'hypertext-markup-language');\ninsert into tags values (default, 'iterationide');\ninsert into tags values (default, 'if-else');\ninsert into tags values (default, 'if-statement');\ninsert into tags values (default, 'immutable-object');\ninsert into tags values (default, 'imperative-programming');\ninsert into tags values (default, 'implicit-parallelism');\ninsert into tags values (default, 'increment');\ninsert into tags values (default, 'indirection-operator');\ninsert into tags values (default, 'inherent-error');\ninsert into tags values (default, 'inheritance');\ninsert into tags values (default, 'inline');\ninsert into tags values (default, 'input/output-statement');\ninsert into tags values (default, 'instance');\ninsert into tags values (default, 'instantiation');\ninsert into tags values (default, 'instructions');\ninsert into tags values (default, 'int');\ninsert into tags values (default, 'integer');\ninsert into tags values (default, 'integrated-development-environment');\ninsert into tags values (default, 'intellij-idea');\ninsert into tags values (default, 'intermediate-language');\ninsert into tags values (default, 'interpreted');\ninsert into tags values (default, 'interpreter');\ninsert into tags values (default, 'invalid');\ninsert into tags values (default, 'ioccc');\ninsert into tags values (default, 'ipc');\ninsert into tags values (default, 'isapi');\ninsert into tags values (default, 'iteration');\ninsert into tags values (default, 'javascript-or-js-logojava');\ninsert into tags values (default, 'java-champion');\ninsert into tags values (default, 'java-ee');\ninsert into tags values (default, 'java-me');\ninsert into tags values (default, 'java-native-language');\ninsert into tags values (default, 'java-reserved-words');\ninsert into tags values (default, 'javabean');\ninsert into tags values (default, 'javac');\ninsert into tags values (default, 'javafx');\ninsert into tags values (default, 'javascript');\ninsert into tags values (default, 'javascriptcore');\ninsert into tags values (default, 'javax');\ninsert into tags values (default, 'jbuilder');\ninsert into tags values (default, 'jcl');\ninsert into tags values (default, 'jdbc');\ninsert into tags values (default, 'jdk');\ninsert into tags values (default, 'jil');\ninsert into tags values (default, 'jit');\ninsert into tags values (default, 'jhtml');\ninsert into tags values (default, 'jni');\ninsert into tags values (default, 'jre');\ninsert into tags values (default, 'jscript');\ninsert into tags values (default, 'json');\ninsert into tags values (default, 'jsp');\ninsert into tags values (default, 'jsr');\ninsert into tags values (default, 'julia');\ninsert into tags values (default, 'jvm');\ninsert into tags values (default, 'karel');\ninsert into tags values (default, 'kit');\ninsert into tags values (default, 'kludge');\ninsert into tags values (default, 'kluge');\ninsert into tags values (default, 'looplabel');\ninsert into tags values (default, 'lambda-calculus');\ninsert into tags values (default, 'language');\ninsert into tags values (default, 'language-processor');\ninsert into tags values (default, 'lexical-analysis');\ninsert into tags values (default, 'lexicon');\ninsert into tags values (default, 'linker');\ninsert into tags values (default, 'lisp');\ninsert into tags values (default, 'live-script');\ninsert into tags values (default, 'literal');\ninsert into tags values (default, 'llvm');\ninsert into tags values (default, 'local-optimum');\ninsert into tags values (default, 'logic-programming');\ninsert into tags values (default, 'logical-operation');\ninsert into tags values (default, 'logo');\ninsert into tags values (default, 'lookup-table');\ninsert into tags values (default, 'loony-bin');\ninsert into tags values (default, 'loop');\ninsert into tags values (default, 'loophole');\ninsert into tags values (default, 'loosely-typed-language');\ninsert into tags values (default, 'low-level-language');\ninsert into tags values (default, 'library');\ninsert into tags values (default, 'lt');\ninsert into tags values (default, 'lua');\ninsert into tags values (default, 'lut');\ninsert into tags values (default, 'matlab-logomachine-language');\ninsert into tags values (default, 'magic-quotes');\ninsert into tags values (default, 'map');\ninsert into tags values (default, 'markup-language');\ninsert into tags values (default, 'math');\ninsert into tags values (default, 'matlab');\ninsert into tags values (default, 'mbean');\ninsert into tags values (default, 'memoization');\ninsert into tags values (default, 'mercurial');\ninsert into tags values (default, 'meta-character');\ninsert into tags values (default, 'metaclass');\ninsert into tags values (default, 'metalanguage');\ninsert into tags values (default, 'method');\ninsert into tags values (default, 'method-overloading');\ninsert into tags values (default, 'metro');\ninsert into tags values (default, 'middleware');\ninsert into tags values (default, 'mod');\ninsert into tags values (default, 'module');\ninsert into tags values (default, 'modulo');\ninsert into tags values (default, 'monkey-testing');\ninsert into tags values (default, 'monte-carlo-method');\ninsert into tags values (default, 'msdn');\ninsert into tags values (default, 'msvc');\ninsert into tags values (default, 'multi-pass-compiler');\ninsert into tags values (default, 'mumps');\ninsert into tags values (default, 'mutex');\ninsert into tags values (default, 'microsoft-dotnet');\ninsert into tags values (default, 'ne');\ninsert into tags values (default, 'dotnet');\ninsert into tags values (default, 'native-compiler');\ninsert into tags values (default, 'native-language');\ninsert into tags values (default, 'natural-language');\ninsert into tags values (default, 'nbsp');\ninsert into tags values (default, 'nda');\ninsert into tags values (default, 'nested-function');\ninsert into tags values (default, 'nested-loop-join');\ninsert into tags values (default, 'newline');\ninsert into tags values (default, 'nil-pointer');\ninsert into tags values (default, 'nim');\ninsert into tags values (default, 'node-js');\ninsert into tags values (default, 'nodelist');\ninsert into tags values (default, 'noncontiguous-data-structure');\ninsert into tags values (default, 'non-disclosure-agreement');\ninsert into tags values (default, 'nonexecutable-statement');\ninsert into tags values (default, 'no-operation-instructions');\ninsert into tags values (default, 'null');\ninsert into tags values (default, 'null-character');\ninsert into tags values (default, 'null-pointer');\ninsert into tags values (default, 'operatorobject-code');\ninsert into tags values (default, 'object-file');\ninsert into tags values (default, 'object-module');\ninsert into tags values (default, 'object-oriented-programming');\ninsert into tags values (default, 'objective-c');\ninsert into tags values (default, 'obfuscated-code');\ninsert into tags values (default, 'ocaml');\ninsert into tags values (default, 'octave');\ninsert into tags values (default, 'odbc');\ninsert into tags values (default, 'oop');\ninsert into tags values (default, 'one-pass-compiler');\ninsert into tags values (default, 'opcode');\ninsert into tags values (default, 'open-database-connectivity');\ninsert into tags values (default, 'opengl-polygon');\ninsert into tags values (default, 'operand');\ninsert into tags values (default, 'operator');\ninsert into tags values (default, 'operator-associatively');\ninsert into tags values (default, 'operator-precedence');\ninsert into tags values (default, 'or-operator');\ninsert into tags values (default, 'overflow-error');\ninsert into tags values (default, 'overload');\ninsert into tags values (default, 'practical-extraction-reporting-languagep-code');\ninsert into tags values (default, 'package');\ninsert into tags values (default, 'parenthesis');\ninsert into tags values (default, 'parse');\ninsert into tags values (default, 'pascal');\ninsert into tags values (default, 'pascal-case');\ninsert into tags values (default, 'pastebin');\ninsert into tags values (default, 'pdl');\ninsert into tags values (default, 'pear');\ninsert into tags values (default, 'perl');\ninsert into tags values (default, 'persistent-memory');\ninsert into tags values (default, 'personaljava');\ninsert into tags values (default, 'php');\ninsert into tags values (default, 'phrase-tag');\ninsert into tags values (default, 'pick');\ninsert into tags values (default, 'pickling');\ninsert into tags values (default, 'picojava');\ninsert into tags values (default, 'pipe');\ninsert into tags values (default, 'pixel-shader');\ninsert into tags values (default, 'pod');\ninsert into tags values (default, 'pointer');\ninsert into tags values (default, 'polymorphism');\ninsert into tags values (default, 'pop');\ninsert into tags values (default, 'positional-parameter');\ninsert into tags values (default, 'private');\ninsert into tags values (default, 'procedural-language');\ninsert into tags values (default, 'procedure');\ninsert into tags values (default, 'process');\ninsert into tags values (default, 'program');\ninsert into tags values (default, 'program-generator');\ninsert into tags values (default, 'program-listing');\ninsert into tags values (default, 'programmable');\ninsert into tags values (default, 'programmer');\ninsert into tags values (default, 'programming');\ninsert into tags values (default, 'programming-in-logic');\ninsert into tags values (default, 'programming-language');\ninsert into tags values (default, 'programming-tools');\ninsert into tags values (default, 'prolog');\ninsert into tags values (default, 'pseudocode');\ninsert into tags values (default, 'pseudolanguage');\ninsert into tags values (default, 'pseudo-operation');\ninsert into tags values (default, 'pseudo-random');\ninsert into tags values (default, 'public');\ninsert into tags values (default, 'purebasic');\ninsert into tags values (default, 'push');\ninsert into tags values (default, 'python');\ninsert into tags values (default, 'python-pickling');\ninsert into tags values (default, 'pythonic');\ninsert into tags values (default, 'qi');\ninsert into tags values (default, 'qt');\ninsert into tags values (default, 'quick-and-dirty');\ninsert into tags values (default, 'return-statementr-programming-language');\ninsert into tags values (default, 'race-condition');\ninsert into tags values (default, 'racket');\ninsert into tags values (default, 'rad');\ninsert into tags values (default, 'random');\ninsert into tags values (default, 'random-seed');\ninsert into tags values (default, 'rcs');\ninsert into tags values (default, 'rdf');\ninsert into tags values (default, 'react');\ninsert into tags values (default, 'react-native');\ninsert into tags values (default, 'real-number');\ninsert into tags values (default, 'recursion');\ninsert into tags values (default, 'recursive');\ninsert into tags values (default, 'regex');\ninsert into tags values (default, 'regular-expression');\ninsert into tags values (default, 'reia');\ninsert into tags values (default, 'relational-algebra');\ninsert into tags values (default, 'religion-of-chi');\ninsert into tags values (default, 'rem');\ninsert into tags values (default, 'remark');\ninsert into tags values (default, 'repeat-counter');\ninsert into tags values (default, 'repl');\ninsert into tags values (default, 'reserved-character');\ninsert into tags values (default, 'reserved-word');\ninsert into tags values (default, 'resource-description-framework');\ninsert into tags values (default, 'return-address');\ninsert into tags values (default, 'return-statement');\ninsert into tags values (default, 'reverse-engineering');\ninsert into tags values (default, 'revision-control');\ninsert into tags values (default, 'rom-basic');\ninsert into tags values (default, 'routine');\ninsert into tags values (default, 'routing-algorithm');\ninsert into tags values (default, 'rpg');\ninsert into tags values (default, 'ruby');\ninsert into tags values (default, 'run-time');\ninsert into tags values (default, 'rust');\ninsert into tags values (default, 'spaghetti-codes-expression');\ninsert into tags values (default, 'safe-font');\ninsert into tags values (default, 'sandbox');\ninsert into tags values (default, 'scala');\ninsert into tags values (default, 'scanf');\ninsert into tags values (default, 'schema-matching');\ninsert into tags values (default, 'scheme-programming-language');\ninsert into tags values (default, 'scratch');\ninsert into tags values (default, 'sdk');\ninsert into tags values (default, 'second-generation-language');\ninsert into tags values (default, 'section');\ninsert into tags values (default, 'security-descriptor-definition-language');\ninsert into tags values (default, 'seed');\ninsert into tags values (default, 'segfault');\ninsert into tags values (default, 'separator');\ninsert into tags values (default, 'sequence');\ninsert into tags values (default, 'server-side');\ninsert into tags values (default, 'server-side-scripting');\ninsert into tags values (default, 'servlet');\ninsert into tags values (default, 'sgml');\ninsert into tags values (default, 'shebang');\ninsert into tags values (default, 'shell-scripts');\ninsert into tags values (default, 'shift');\ninsert into tags values (default, 'short-circuit-operator');\ninsert into tags values (default, 'signedness');\ninsert into tags values (default, 'simulated-annealing');\ninsert into tags values (default, 'single-step');\ninsert into tags values (default, 'smalltalk');\ninsert into tags values (default, 'smil');\ninsert into tags values (default, 'snippet');\ninsert into tags values (default, 'soap');\ninsert into tags values (default, 'socket');\ninsert into tags values (default, 'soft');\ninsert into tags values (default, 'software-development-phases');\ninsert into tags values (default, 'software-development-process');\ninsert into tags values (default, 'software-engineering');\ninsert into tags values (default, 'software-library');\ninsert into tags values (default, 'software-life-cycle');\ninsert into tags values (default, 'source');\ninsert into tags values (default, 'source-code');\ninsert into tags values (default, 'source-computer');\ninsert into tags values (default, 'source-data');\ninsert into tags values (default, 'sourceforge');\ninsert into tags values (default, 'spaghetti-code');\ninsert into tags values (default, 'sparse-matrix');\ninsert into tags values (default, 'sparsity');\ninsert into tags values (default, 'special-purpose-language');\ninsert into tags values (default, 'spl');\ninsert into tags values (default, 'spooling');\ninsert into tags values (default, 'sql');\ninsert into tags values (default, 'stack');\ninsert into tags values (default, 'stack-pointer');\ninsert into tags values (default, 'standard-attribute');\ninsert into tags values (default, 'statement');\ninsert into tags values (default, 'stdin');\ninsert into tags values (default, 'strong-typed-language');\ninsert into tags values (default, 'stubroutine');\ninsert into tags values (default, 'stylesheet');\ninsert into tags values (default, 'subprogram');\ninsert into tags values (default, 'subroutine');\ninsert into tags values (default, 'subscript');\ninsert into tags values (default, 'substring');\ninsert into tags values (default, 'subversion');\ninsert into tags values (default, 'superclass');\ninsert into tags values (default, 'switch-statement');\ninsert into tags values (default, 'syntactic-sugar');\ninsert into tags values (default, 'syntax-error');\ninsert into tags values (default, 'system-development');\ninsert into tags values (default, 'systems-engineer');\ninsert into tags values (default, 'systems-programming-language');\ninsert into tags values (default, 'tupletail-recursion');\ninsert into tags values (default, 'tcl');\ninsert into tags values (default, 'tcl/tk');\ninsert into tags values (default, 'ternary-operator');\ninsert into tags values (default, 'theoretical-computer-science-');\ninsert into tags values (default, 'third-generation-language');\ninsert into tags values (default, 'thread');\ninsert into tags values (default, 'thunk');\ninsert into tags values (default, 'tk');\ninsert into tags values (default, 'token');\ninsert into tags values (default, 'transcompiler');\ninsert into tags values (default, 'true');\ninsert into tags values (default, 'true-basic');\ninsert into tags values (default, 'trunk');\ninsert into tags values (default, 'tuple');\ninsert into tags values (default, 'turbo-pascal');\ninsert into tags values (default, 'turing-completeness');\ninsert into tags values (default, 'unary-operator');\ninsert into tags values (default, 'undefined');\ninsert into tags values (default, 'undefined-variable');\ninsert into tags values (default, 'underflow');\ninsert into tags values (default, 'unescape');\ninsert into tags values (default, 'unit-test');\ninsert into tags values (default, 'unshift');\ninsert into tags values (default, 'value');\ninsert into tags values (default, 'var');\ninsert into tags values (default, 'variable');\ninsert into tags values (default, 'vb');\ninsert into tags values (default, 'vector');\ninsert into tags values (default, 'vhdl');\ninsert into tags values (default, 'vim');\ninsert into tags values (default, 'visual-basic');\ninsert into tags values (default, 'visual-studio');\ninsert into tags values (default, 'void');\ninsert into tags values (default, 'waterfall-model');\ninsert into tags values (default, 'web-development');\ninsert into tags values (default, 'webgl');\ninsert into tags values (default, 'while');\ninsert into tags values (default, 'whole-number');\ninsert into tags values (default, 'wml');\ninsert into tags values (default, 'workspace');\ninsert into tags values (default, 'xml');\ninsert into tags values (default, 'xna');\ninsert into tags values (default, 'xor-operator');\ninsert into tags values (default, 'xoxo');\ninsert into tags values (default, 'xsl');\ninsert into tags values (default, 'xslt');\ninsert into tags values (default, 'y-combinator');\ninsert into tags values (default, 'yaml');\ninsert into tags values (default, 'z-buffering');\ninsert into tags values (default, 'zombie');\n\ndown:\ndrop table users;\ndrop table questions;\ndrop table comments;\ndrop table tags;\ndrop table question_votes;\ndrop table comment_votes;\ndrop table snippets;\n"
  },
  {
    "path": "platform/migrations/migrations/20180901170431-triggers.sql",
    "content": "up:\ndrop trigger if exists question_vote_insert_trigger;\ndelimiter $\ncreate trigger question_vote_insert_trigger after insert on question_votes for each row begin\n    update questions set score = score + NEW.value where question_id = NEW.question_id;\nend$\ndelimiter ;\n\ndrop trigger if exists question_vote_delete_trigger;\ndelimiter $\ncreate trigger question_vote_delete_trigger after delete on question_votes for each row begin\n    update questions set score = score - OLD.value where question_id = OLD.question_id;\nend$\ndelimiter ;\n\ndrop trigger if exists comment_vote_insert_trigger;\ndelimiter $\ncreate trigger comment_vote_insert_trigger after insert on comment_votes for each row begin\n    update comments set score = score + NEW.value where comment_id = NEW.comment_id;\nend$\ndelimiter ;\n\ndrop trigger if exists comment_vote_delete_trigger;\ndelimiter $\ncreate trigger comment_vote_delete_trigger after delete on comment_votes for each row begin\n    update comments set score = score - OLD.value where comment_id = OLD.comment_id;\nend$\ndelimiter ;\n\ndrop trigger if exists comment_insert_trigger;\ndelimiter $\ncreate trigger comment_insert_trigger after insert on comments for each row begin\n    update questions set comments = comments + 1 where question_id = NEW.question_id;\nend$\ndelimiter ;\n\ndrop trigger if exists comment_delete_trigger;\ndelimiter $\ncreate trigger comment_delete_trigger after delete on comments for each row begin\n    update questions set comments = comments - 1 where question_id = OLD.question_id;\nend$\ndelimiter ;\n\ndown:\n"
  },
  {
    "path": "platform/migrations/migrations/20180903004942-display-name.sql",
    "content": "up:\nalter table users add display_name varchar(64) not null after is_staff;\nupdate users set display_name = username;\n\ndown:\nalter table users drop column display_name;\n"
  },
  {
    "path": "platform/migrations/migrations/20180903013450-question-tags.sql",
    "content": "up:\ncreate table question_tags (\n    question_tag_id int unsigned not null auto_increment,\n    question_id int not null default 0,\n    tag_id int not null default 0,\n    primary key (question_tag_id),\n    key question_id (question_id),\n    key tag_id (tag_id)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table question_tags;\n"
  },
  {
    "path": "platform/migrations/migrations/20180903180404-default-avatar.sql",
    "content": "up:\nalter table users modify avatar_url varchar(128) not null default '/avatars/default.png' after discord_api;\n\ndown:\nalter table users modify avatar_url varchar(128) null after discord_api;\n"
  },
  {
    "path": "platform/migrations/migrations/20180903222426-views-field.sql",
    "content": "up:\nalter table questions add views int unsigned not null default 0 after score;\n\ndown:\nalter table questions drop column views;\n"
  },
  {
    "path": "platform/migrations/migrations/20180905220531-notification-table.sql",
    "content": "up:\ncreate table notifications (\n    notification_id int unsigned not null auto_increment,\n    user_id int unsigned not null,\n    type tinyint unsigned not null,\n    entity_type tinyint unsigned not null,\n    entity_id int unsigned not null,\n    message varchar(512) not null,\n    created_at datetime not null,\n    primary key (notification_id),\n    key user_id (user_id),\n    key type (type),\n    key entity_type (entity_type),\n    key entity_id (entity_id)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table notifications;\n"
  },
  {
    "path": "platform/migrations/migrations/20180908000333-new-tags.sql",
    "content": "up:\ntruncate tags;\n\ninsert into tags values (default, 'java');\ninsert into tags values (default, 'c');\ninsert into tags values (default, 'python');\ninsert into tags values (default, 'c++');\ninsert into tags values (default, 'visual-basic-dot-net');\ninsert into tags values (default, 'c#');\ninsert into tags values (default, 'php');\ninsert into tags values (default, 'javascript');\ninsert into tags values (default, 'sql');\ninsert into tags values (default, 'objective-c');\ninsert into tags values (default, 'delphi-object-pascal');\ninsert into tags values (default, 'ruby');\ninsert into tags values (default, 'matlab');\ninsert into tags values (default, 'assembly-language');\ninsert into tags values (default, 'swift');\ninsert into tags values (default, 'go');\ninsert into tags values (default, 'perl');\ninsert into tags values (default, 'r');\ninsert into tags values (default, 'pl-sql');\ninsert into tags values (default, 'visual-basic');\ninsert into tags values (default, 'sas');\ninsert into tags values (default, 'dart');\ninsert into tags values (default, 'd');\ninsert into tags values (default, 'scratch');\ninsert into tags values (default, 'f#');\ninsert into tags values (default, 'cobol');\ninsert into tags values (default, 'scala');\ninsert into tags values (default, 'abap');\ninsert into tags values (default, 'fortran');\ninsert into tags values (default, 'lua');\ninsert into tags values (default, 'rust');\ninsert into tags values (default, 'transact-sql');\ninsert into tags values (default, 'lisp');\ninsert into tags values (default, 'groovy');\ninsert into tags values (default, 'labview');\ninsert into tags values (default, 'prolog');\ninsert into tags values (default, 'ada');\ninsert into tags values (default, 'logo');\ninsert into tags values (default, 'julia');\ninsert into tags values (default, 'haskell');\ninsert into tags values (default, 'apex');\ninsert into tags values (default, 'kotlin');\ninsert into tags values (default, 'bash');\ninsert into tags values (default, 'ladder-logic');\ninsert into tags values (default, 'alice');\ninsert into tags values (default, 'tcl');\ninsert into tags values (default, 'clojure');\ninsert into tags values (default, 'postscript');\ninsert into tags values (default, 'scheme');\ninsert into tags values (default, 'awk');\ninsert into tags values (default, 'actionscript');\ninsert into tags values (default, 'bc');\ninsert into tags values (default, 'bourne-shell');\ninsert into tags values (default, 'c-shell');\ninsert into tags values (default, 'cfml');\ninsert into tags values (default, 'coffeescript');\ninsert into tags values (default, 'common-lisp');\ninsert into tags values (default, 'crystal');\ninsert into tags values (default, 'ct');\ninsert into tags values (default, 'elixir');\ninsert into tags values (default, 'elm');\ninsert into tags values (default, 'emacs-lisp');\ninsert into tags values (default, 'erlang');\ninsert into tags values (default, 'forth');\ninsert into tags values (default, 'hack');\ninsert into tags values (default, 'icon');\ninsert into tags values (default, 'inform');\ninsert into tags values (default, 'io');\ninsert into tags values (default, 'j');\ninsert into tags values (default, 'korn-shell');\ninsert into tags values (default, 'livecode');\ninsert into tags values (default, 'maple');\ninsert into tags values (default, 'mercury');\ninsert into tags values (default, 'ml');\ninsert into tags values (default, 'monkey');\ninsert into tags values (default, 'ocaml');\ninsert into tags values (default, 'opencl');\ninsert into tags values (default, 'openedge-abl');\ninsert into tags values (default, 'oz');\ninsert into tags values (default, 'powershell');\ninsert into tags values (default, 'q');\ninsert into tags values (default, 'racket');\ninsert into tags values (default, 'ring');\ninsert into tags values (default, 'rpg');\ninsert into tags values (default, 's');\ninsert into tags values (default, 'snap!');\ninsert into tags values (default, 'spark');\ninsert into tags values (default, 'spss');\ninsert into tags values (default, 'tex');\ninsert into tags values (default, 'typescript');\ninsert into tags values (default, 'vhdl');\ninsert into tags values (default, 'emkc');\ninsert into tags values (default, 'linux');\ninsert into tags values (default, 'ubuntu');\n\ndown:\ntruncate tags;\n"
  },
  {
    "path": "platform/migrations/migrations/20180915035412-code-rooms.sql",
    "content": "up:\ncreate table code_rooms (\n    code_room_id int unsigned not null auto_increment,\n    user_id int unsigned null,\n    hash varchar(40) not null,\n    code mediumtext not null,\n    created_at datetime not null,\n    primary key (code_room_id),\n    key user_id (user_id),\n    key hash (hash),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table code_rooms;\n"
  },
  {
    "path": "platform/migrations/migrations/20180917013146-snippet-language.sql",
    "content": "up:\nalter table snippets add language varchar(32) not null after hash;\nupdate snippets set language = 'javascript';\n\ndown:\nalter table snippets drop column language;\n"
  },
  {
    "path": "platform/migrations/migrations/20180930153901-video-requests.sql",
    "content": "up:\ncreate table video_requests (\n    video_request_id int unsigned not null auto_increment,\n    user_id int not null,\n    name varchar(255) not null,\n    created_at datetime not null,\n    primary key (video_request_id),\n    key user_id (user_id)\n)engine=innodb default charset=utf8;\n\ncreate table video_request_votes (\n    video_request_vote_id int unsigned not null auto_increment,\n    video_request_id int unsigned not null,\n    user_id int unsigned not null,\n    primary key (video_request_vote_id),\n    key video_request_id (video_request_id),\n    key user_id (user_id)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table video_requests;\ndrop table video_request_votes;\n"
  },
  {
    "path": "platform/migrations/migrations/20181005005500-challenges-tables.sql",
    "content": "up:\ncreate table challenges (\n    challenge_id int unsigned not null auto_increment,\n    difficulty tinyint unsigned not null,\n    points int unsigned not null,\n    folder varchar(64) not null,\n    name varchar(128) not null,\n    description varchar(512) not null,\n    primary key (challenge_id),\n    key difficulty (difficulty),\n    key points (points)\n)engine=innodb default charset=utf8;\n\ninsert into challenges values (1, 1, 10, '1_reverse_string', 'Reverse a string', 'Just take any given string and output it in reverse, pretty easy, right?');\n\ncreate table user_challenges (\n    user_challenge_id int unsigned not null auto_increment,\n    user_id int unsigned not null,\n    challenge_id int unsigned not null,\n    language varchar(8) not null,\n    solution mediumtext not null,\n    created_at datetime not null,\n    primary key (user_challenge_id),\n    key user_id (user_id),\n    key challenge_id (challenge_id),\n    key language (language),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table challenges;\ndrop table user_challenges;\n"
  },
  {
    "path": "platform/migrations/migrations/20181021204739-chats-table.sql",
    "content": "up:\ncreate table discord_chat_messages (\n    discord_chat_message_id int unsigned not null auto_increment,\n    hash varchar(40) not null,\n    channel varchar(32) not null,\n    user varchar(32) not null,\n    message varchar(8192) not null,\n    created_at datetime not null,\n    primary key (discord_chat_message_id),\n    unique hash (hash),\n    key channel (channel),\n    key user (user),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table discord_chat_messages;\n"
  },
  {
    "path": "platform/migrations/migrations/20181107035714-new-challenge.sql",
    "content": "up:\ninsert into challenges values (2, 1, 10, '2_number_frequency', 'Count number frequency', 'Take a string of numbers and output the one which appears the most.');\n\ndown:\ndelete from challenges where challenge_id = 2;\n"
  },
  {
    "path": "platform/migrations/migrations/20181111035714-new-challenge.sql",
    "content": "up:\ninsert into challenges values (3, 1, 10, '3_list_sum', 'Sum a list of numbers', 'Take a string of comma separated numbers and print out the sum.');\n\ndown:\ndelete from challenges where challenge_id = 3;\n"
  },
  {
    "path": "platform/migrations/migrations/20181119035714-new-challenge.sql",
    "content": "up:\ninsert into challenges values (4, 3, 50, '4_invalid_json', 'Detect and fix invalid JSON', 'Take an invalid JSON string and figure out where the errors are and make it valid.');\ninsert into challenges values (5, 2, 30, '5_binary_convert', 'Convert string to binary', 'Take three lowercase letters and print out binary.');\n\ndown:\ndelete from challenges where challenge_id = 4;\ndelete from challenges where challenge_id = 5;\n"
  },
  {
    "path": "platform/migrations/migrations/20181121035714-discord-rank-field.sql",
    "content": "up:\nalter table users add discord_rank tinyint unsigned default null after discord_api;\n\ndown:\nalter table users drop column discord_rank;\n"
  },
  {
    "path": "platform/migrations/migrations/20181229135021-new-challenge.sql",
    "content": "up:\ninsert into challenges values (6, 2, 30, '6_fibonacci_sequence', 'Fibonacci Numbers', 'Start with one Fibonacci sequence number, then calculate more from there.');\ninsert into challenges values (7, 2, 30, '7_check_permutation', 'Check scrambled string', 'Given two strings of equal length, figure out if one is a scramble of the other.');\n\ndown:\ndelete from challenges where challenge_id = 6;\ndelete from challenges where challenge_id = 7;\n"
  },
  {
    "path": "platform/migrations/migrations/20190104235301-new-challenge.sql",
    "content": "up:\ninsert into challenges values (8, 1, 10, '8_sort_integers', 'Integer list sorting', 'Take a list of integers and print it after sorting it in descending order.');\ninsert into challenges values (9, 3, 50, '9_roman_numerals', 'Roman Numeral conversion', 'Take a roman numeral(<1000 in value) and print its corresponding value in the decimal system of numbers.');\n\ndown:\ndelete from challenges where challenge_id = 8;\ndelete from challenges where challenge_id = 9;\n"
  },
  {
    "path": "platform/migrations/migrations/20190405004828-new-challenge.sql",
    "content": "up:\ninsert into challenges values (10, 3, 50, '10_pig_latin', 'Pig latin translator', 'Take a sentence/phrase in pig latin, translate it to English.');\n\ndown:\ndelete from challenges where challenge_id = 10;\n"
  },
  {
    "path": "platform/migrations/migrations/20190611224428-new-challenge.sql",
    "content": "up:\ninsert into challenges values (11, 2, 30, '11_array_neighbor', 'Zipper merge', 'Merge two arrays in a zipper-like fashion.');\nupdate challenges set difficulty = 3, points = 50 where challenge_id = 10;\n\ndown:\nupdate challenges set difficulty = 1, points = 10 where challenge_id = 10;\ndelete from challenges where challenge_id = 11;\n"
  },
  {
    "path": "platform/migrations/migrations/20190622133430-new-challenge.sql",
    "content": "up:\ninsert into challenges values (12, 1, 10, '12_longest_word', 'Find Longest Word', 'Given a string with multiple words, return the longest word.');\n\ndown:\ndelete from challenges where challenge_id = 12;\n"
  },
  {
    "path": "platform/migrations/migrations/20190622224428-discord-id-chat-messages.sql",
    "content": "up:\nalter table discord_chat_messages add discord_id varchar(32) not null after user;\nalter table discord_chat_messages add index discord_id (discord_id);\n\ndown:\nalter table discord_chat_messages drop column discord_id;\n"
  },
  {
    "path": "platform/migrations/migrations/20190624224428-script-town.sql",
    "content": "up:\ncreate table cli_scripts (\n    cli_script_id int unsigned not null auto_increment,\n    user_id int unsigned not null,\n    is_public tinyint unsigned not null default 0,\n    is_safe tinyint unsigned not null default 0,\n    title varchar(256) not null,\n    content mediumtext not null,\n    created_at datetime not null,\n    primary key (cli_script_id),\n    key user_id (user_id),\n    key is_public (is_public),\n    key is_safe (is_safe),\n    key title (title),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table cli_scripts;\n"
  },
  {
    "path": "platform/migrations/migrations/20191023224428-stickers.sql",
    "content": "up:\ncreate table sticker_orders (\n    sticker_order_id int unsigned not null auto_increment,\n    is_fulfilled tinyint unsigned not null default 0,\n    tx varchar(128) null,\n    coupon varchar(128) null,\n    quantity int unsigned not null,\n    cost decimal(5,2) null,\n    name varchar(256) not null,\n    email varchar(256) not null,\n    address varchar(256) not null,\n    created_at datetime not null,\n    primary key (sticker_order_id),\n    key is_fulfilled (is_fulfilled),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table sticker_orders;\n"
  },
  {
    "path": "platform/migrations/migrations/20191101133430-new-challenge.sql",
    "content": "up:\ninsert into challenges values (13, 2, 30, '13_most_common_character', 'Find Most Common Characters', 'Given a string with multiple words, find the most common character.');\n\ndown:\ndelete from challenges where challenge_id = 13;\n"
  },
  {
    "path": "platform/migrations/migrations/20191201133430-new-challenge.sql",
    "content": "up:\ninsert into challenges values (14, 2, 30, '14_number_digit_sum', 'Digit Sum Even or Odd', 'Given a number, find out if the sum of the digits is even or odd.');\n\ndown:\ndelete from challenges where challenge_id = 14;\n"
  },
  {
    "path": "platform/migrations/migrations/20200711133430-piston-stats.sql",
    "content": "up:\ncreate table piston_runs (\n    piston_run_id int unsigned not null auto_increment,\n    server varchar(64) not null,\n    user varchar(32) not null,\n    discord_id varchar(32) not null,\n    language varchar(32) not null,\n    source text,\n    created_at datetime not null,\n    primary key (piston_run_id),\n    key server (server),\n    key user (user),\n    key discord_id (discord_id),\n    key language (language),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table piston_runs;\n"
  },
  {
    "path": "platform/migrations/migrations/20200711133431-piston-stats.sql",
    "content": "up:\nalter table piston_runs change discord_id user_id varchar(32) not null;\nalter table piston_runs add server_id varchar(32) not null after server;\n\ndown:\nalter table piston_runs change user_id discord_id varchar(32) not null;\nalter table piston_runs drop column server_id;\n"
  },
  {
    "path": "platform/migrations/migrations/20200802133431-new-challenge.sql",
    "content": "up:\ninsert into challenges values (15, 1, 10, '15_binary_cookie', 'Find The Cookie', 'Given a binary string, a cookie, find its place in the binary cookie jar.');\n\ndown:\ndelete from challenges where challenge_id = 15;"
  },
  {
    "path": "platform/migrations/migrations/20200813092823-new-challenge.sql",
    "content": "up:\ninsert into challenges values (16, 1, 10, '16_spiral_corner', 'Spiral Sum', 'Given the size of a spiral, calculate the sum of the four corners.');\n\ndown:\ndelete from challenges where challenge_id = 16;\n"
  },
  {
    "path": "platform/migrations/migrations/20200825133432-new-challenge.sql",
    "content": "up:\ninsert into challenges values (17, 2, 30, '17_quadratic_calculator', 'Answer The Quadratic', 'Given a quadratic find the decimal values of x');\n\ndown:\ndelete from challenges where challenge_id = 17;\n"
  },
  {
    "path": "platform/migrations/migrations/20200830224428-contests-tables.sql",
    "content": "up:\ncreate table contests (\n    contest_id int unsigned not null auto_increment,\n    name varchar(128) not null,\n    description mediumtext not null,\n    start_date datetime not null,\n    end_date datetime not null,\n    input text not null,\n    output text not null,\n    created_at datetime not null,\n    primary key (contest_id),\n    key start_date (start_date),\n    key end_date (end_date),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ninsert into contests values (1, 'First Contest', 'Test Description', '2020-08-29 00:00:00', '2020-09-20 23:59:59', '5', '5', now());\n\ncreate table contest_submissions (\n    contest_submission_id int unsigned not null auto_increment,\n    user_id int unsigned not null,\n    contest_id int unsigned not null,\n    language varchar(32) not null,\n    solution mediumtext not null,\n    length int unsigned not null,\n    award_place int unsigned null,\n    award_points int unsigned null,\n    created_at datetime not null,\n    primary key (contest_submission_id),\n    key user_id (user_id),\n    key contest_id (contest_id),\n    key language (language),\n    key award_place (award_place),\n    key award_points (award_points),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ninsert into contest_submissions values (default, 1, 1, 'javascript', 'console.log(1)', 14, null, null, now());\n\ndown:\ndrop table contests;\ndrop table contest_submissions;\n"
  },
  {
    "path": "platform/migrations/migrations/20200905203703-contest-draft-field.sql",
    "content": "up:\nalter table contests add draft tinyint unsigned not null default 1 after contest_id;\n\ndown:\nalter table contests drop column draft;\n"
  },
  {
    "path": "platform/migrations/migrations/20200918012206-cleanup-old-tables.sql",
    "content": "up:\ndrop table code_rooms;\ndrop table comment_votes;\ndrop table comments;\ndrop table notifications;\ndrop table question_tags;\ndrop table question_votes;\ndrop table questions;\ndrop table video_request_votes;\ndrop table video_requests;\n\ndown:\nCREATE TABLE `code_rooms` (\n  `code_room_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `user_id` int(10) unsigned DEFAULT NULL,\n  `hash` varchar(40) NOT NULL,\n  `code` mediumtext NOT NULL,\n  `created_at` datetime NOT NULL,\n  PRIMARY KEY (`code_room_id`),\n  KEY `user_id` (`user_id`),\n  KEY `hash` (`hash`),\n  KEY `created_at` (`created_at`)\n) ENGINE=InnoDB AUTO_INCREMENT=274 DEFAULT CHARSET=utf8;\n\nCREATE TABLE `comment_votes` (\n  `comment_vote_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `comment_id` int(10) unsigned NOT NULL,\n  `user_id` int(10) unsigned NOT NULL,\n  `value` tinyint(4) NOT NULL,\n  PRIMARY KEY (`comment_vote_id`),\n  KEY `comment_id` (`comment_id`),\n  KEY `user_id` (`user_id`),\n  KEY `value` (`value`)\n) ENGINE=InnoDB AUTO_INCREMENT=372 DEFAULT CHARSET=utf8;\n\nCREATE TABLE `comments` (\n  `comment_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `question_id` int(10) unsigned NOT NULL,\n  `base_id` int(10) unsigned DEFAULT NULL,\n  `parent_id` int(10) unsigned DEFAULT NULL,\n  `user_id` int(10) unsigned NOT NULL,\n  `comment` mediumtext NOT NULL,\n  `depth` int(11) NOT NULL DEFAULT '0',\n  `score` int(11) NOT NULL DEFAULT '0',\n  `created_at` datetime NOT NULL,\n  PRIMARY KEY (`comment_id`),\n  KEY `question_id` (`question_id`),\n  KEY `base_id` (`base_id`),\n  KEY `parent_id` (`parent_id`),\n  KEY `user_id` (`user_id`),\n  KEY `depth` (`depth`),\n  KEY `score` (`score`),\n  KEY `created_at` (`created_at`)\n) ENGINE=InnoDB AUTO_INCREMENT=316 DEFAULT CHARSET=utf8;\n\nCREATE TABLE `notifications` (\n  `notification_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `user_id` int(10) unsigned NOT NULL,\n  `type` tinyint(3) unsigned NOT NULL,\n  `entity_type` tinyint(3) unsigned NOT NULL,\n  `entity_id` int(10) unsigned NOT NULL,\n  `message` varchar(512) NOT NULL,\n  `created_at` datetime NOT NULL,\n  PRIMARY KEY (`notification_id`),\n  KEY `user_id` (`user_id`),\n  KEY `type` (`type`),\n  KEY `entity_type` (`entity_type`),\n  KEY `entity_id` (`entity_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `question_tags` (\n  `question_tag_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `question_id` int(11) NOT NULL DEFAULT '0',\n  `tag_id` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`question_tag_id`),\n  KEY `question_id` (`question_id`),\n  KEY `tag_id` (`tag_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8;\n\nCREATE TABLE `question_votes` (\n  `question_vote_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `question_id` int(10) unsigned NOT NULL,\n  `user_id` int(10) unsigned NOT NULL,\n  `value` tinyint(4) NOT NULL,\n  PRIMARY KEY (`question_vote_id`),\n  KEY `question_id` (`question_id`),\n  KEY `user_id` (`user_id`),\n  KEY `value` (`value`)\n) ENGINE=InnoDB AUTO_INCREMENT=157 DEFAULT CHARSET=utf8;\n\nCREATE TABLE `questions` (\n  `question_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `user_id` int(10) unsigned NOT NULL,\n  `title` varchar(128) NOT NULL,\n  `question` mediumtext NOT NULL,\n  `score` int(11) NOT NULL DEFAULT '0',\n  `views` int(10) unsigned NOT NULL DEFAULT '0',\n  `comments` int(10) unsigned NOT NULL DEFAULT '0',\n  `created_at` datetime NOT NULL,\n  PRIMARY KEY (`question_id`),\n  KEY `user_id` (`user_id`),\n  KEY `score` (`score`),\n  KEY `comments` (`comments`),\n  KEY `created_at` (`created_at`)\n) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8;\n\nCREATE TABLE `video_request_votes` (\n  `video_request_vote_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `video_request_id` int(10) unsigned NOT NULL,\n  `user_id` int(10) unsigned NOT NULL,\n  PRIMARY KEY (`video_request_vote_id`),\n  KEY `video_request_id` (`video_request_id`),\n  KEY `user_id` (`user_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=374 DEFAULT CHARSET=utf8;\n\nCREATE TABLE `video_requests` (\n  `video_request_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `user_id` int(11) NOT NULL,\n  `name` varchar(255) NOT NULL,\n  `created_at` datetime NOT NULL,\n  PRIMARY KEY (`video_request_id`),\n  KEY `user_id` (`user_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=63 DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "platform/migrations/migrations/20200918012216-award-table.sql",
    "content": "up:\ncreate table awards (\n    award_id int unsigned not null auto_increment,\n    type int unsigned not null,\n    points int unsigned not null,\n    user_id int unsigned not null,\n    ref_type int unsigned null,\n    ref_id int unsigned null,\n    created_at datetime not null,\n    primary key (award_id),\n    key type (type),\n    key points (points),\n    key user_id (user_id),\n    key ref_type (ref_type),\n    key ref_id (ref_id),\n    key created_at (created_at)\n)engine=innodb default charset=utf8;\n\ndown:\ndrop table awards;\n"
  },
  {
    "path": "platform/migrations/migrations/20210117125516-add-html-to-challenges.sql",
    "content": "up:\nalter table challenges add html mediumtext default null after description;\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable could contain a variety of string values. Regardless of value, you''ll need to\n        reverse the string and print it out.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            The string to reverse\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Simple string</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> cat</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> tac</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Complex string</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> sd#$)(&*09&M0</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 0M&90*&()$#ds</div>\n        </div>\n    </div>\n</div>\n' where folder = '1_reverse_string';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable will be a string of many numbers. You''ll need to print out the number which appears the\n        most times in that string.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            String of numbers\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">String of numbers</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 08989082882348823838</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 8</div>\n        </div>\n    </div>\n</div>\n' where folder = '2_number_frequency';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable could contain a list of integer values. Regardless of value, you''ll need to\n        print out the sum of the list.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            The list to add\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Short list</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 2,5,1</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 8</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Long list</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 3,9,10,5,2,7,9,2</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 47</div>\n        </div>\n    </div>\n</div>\n' where folder = '3_list_sum';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable will contain a string of invalid JSON. However, each invalid JSON string received can be fixed\n        by making one or more single character changes. Only three possible things may be wrong with the JSON string:\n        1) missing leading or trailing brace, 2) unquoted JSON string value, 3) missing comma between properties.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            A string of invalid JSON\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Single Problem</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> {\"name\":\"em\"</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> {\"name\":\"em\"}</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Multiple Problems</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> \"name\":\"em</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> {\"name\":\"em\"}</div>\n        </div>\n    </div>\n</div>\n' where folder = '4_invalid_json';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable will contain a string of three lowercase letters. From this, you''ll need to convert it\n        to binary and print out the 24 number representation of those letters in binary.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            Three lowercase letters\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Case</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Letter</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> abc</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 011000010110001001100011</div>\n        </div>\n    </div>\n</div>\n' where folder = '5_binary_convert';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable will contain a fibonacci sequence number. Your job is to calculate the next n digits.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <p>\n                <span class=\"badge badge-info\">value1</span><br />\n                The starting number\n            </p>\n            <p>\n                <span class=\"badge badge-info\">value2</span><br />\n                n number to calculate after value1\n            </p>\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Small Number</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 5</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value2</span> 2</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 8,13</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Large Numbers</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 34</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value2</span> 7</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 55,89,144,233,377,610,987</div>\n        </div>\n    </div>\n</div>\n' where folder = '6_fibonacci_sequence';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable will contain two strings of equal length, separated by a comma. You have\n        to check whether the second string is a permutation of the first string. Print \"Yes\" if it is,\n        \"No\" if not.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            Two strings separated by a comma\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Case</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Permutation</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> brian,airbn</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> Yes</div>\n        </div>\n    </div>\n</div>\n' where folder = '7_check_permutation';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable will contain a list of integers, you have to sort the list in descending\n        order and print it.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            The list to sort\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Short list</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 3,4,-9</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 4,3,-9</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Long list</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 3,9,10,5,2,7,9,2</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 10,9,9,7,5,3,2,2</div>\n        </div>\n    </div>\n</div>\n' where folder = '8_sort_integers';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable will contain a roman numeral less than 1000 in value. Print the\n        corresponding value of the roman numeral in the decimal system of numbers.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            The roman numeral\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Small Roman Numeral</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> VI</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 6</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Large Roman Numeral</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> CDVII</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 407</div>\n        </div>\n    </div>\n</div>\n' where folder = '9_roman_numerals';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        Your input variable will contain a sentence/phrase in pig latin. Your job is to translate it to english. You add \"yay\" if the word starts with a vowel. Otherwise move the starting consonant sequence (w, wr, sch, ...) to the end of the word and add \"ay\" plus a dash.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            Sentence/phrase in pig latin.\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Short phrase</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> ayay imple-say est-tay ase-cay</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> a simple test case</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Long phrase</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> ig-pay atin-lay isyay usedyay inyay ools-schay o-tay each-tay anguage-lay onstructs-cay</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> pig latin is used in schools to teach language constructs</div>\n        </div>\n    </div>\n</div>\n' where folder = '10_pig_latin';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        You''ll get two inputs, each will be a comma separated list of numbers. Each input will contain\n        the same amount of numbers. You''ll need to merge the two lists by inserting numbers from value2 into value1.\n        Each number from value2 should be inserted every other number starting after the first number in value 1.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <p>\n                <span class=\"badge badge-info\">value1</span><br />\n                First comma separated list of numbers\n            </p>\n            <p>\n                <span class=\"badge badge-info\">value2</span><br />\n                Second comma separated list of numbers\n            </p>\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Short List</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 9,5</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value2</span> 7,10</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 9,7,5,10</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Large List</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 34,18,4,102</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value2</span> 15,19,120,64</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 34,15,18,19,4,120,102,64</div>\n        </div>\n    </div>\n</div>\n' where folder = '11_array_neighbor';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        You''ll get one input, a string with multiple words. Return the longest word in the string. If the input\n        contains multiple words that are the largest length, return a string that contains all of the words in\n        the same order they are provided.\n\n        All returned strings should be lowercase and trimmed of whitespace.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <p>\n                <span class=\"badge badge-info\">value1</span><br />\n                Single string with multiple words.\n            </p>\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Regular</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> run,barn,yellow,barracuda,shark,fish,swim</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> barracuda</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Same Size</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> fishes,sam,gollum,sauron,frodo,balrog</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> fishes,gollum,sauron,balrog</div>\n        </div>\n    </div>\n</div>\n' where folder = '12_longest_word';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n        You will be given a string and your job is to find the most common character in that\n        string. If there are two characters which appear the same amount of times and are the\n        largest amount, you should output both separated by a comma in the order they first appeared.\n    </div>\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            A long or short string\n        </div>\n    </div>\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n        <div class=\"test_case\">\n            <div class=\"f700\">Short phrase</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> A test case</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> t,e,s</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Long phrase</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> The way this mode works is by looking for the mode of the characters of any given string</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> o</div>\n        </div>\n    </div>\n</div>\n' where folder = '13_most_common_character';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n        You will be given an integer and your job is to determine the sum made up by each individual digit.\n        Once you have the sum, determine if the sum is even or odd and then print out either \"even\" or \"odd\".\n    </div>\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n        <div class=\"input\">\n            <span class=\"badge badge-info\">value1</span><br />\n            An integer\n        </div>\n    </div>\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n        <div class=\"test_case\">\n            <div class=\"f700\">Short number</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 31</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> even</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Long number</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 662638</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> odd</div>\n        </div>\n    </div>\n</div>\n' where folder = '14_number_digit_sum';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        You''ll get one input string formatted as ''[cookie],[cookie jar]''. Return the sum of the starting index number of the\n        cookie in the cookie jar and the ending index number of the cookie in the cookie jar.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <p>\n                <span class=\"badge badge-info\">value1</span><br />\n                Single string formatted as ''[cookie],[cookie jar]''.\n            </p>\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Regular Cookie</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 10000101,100001111000010110100001</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 23</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Big Cookie</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 1010100100110110,1111010000011111111000111010100100110110</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 63</div>\n        </div>\n    </div>\n</div>\n' where folder = '15_binary_cookie';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n        Given a size for a number spiral, you count clockwise with numbers. A 3x3 is 3 columns by 3 rows.\n        <pre class=\"easy\">\n        2x2  3x3    4x4\n        1 2  7 8 9   7  8  9 10\n        4 3  6 1 2   6  1  2 11\n             5 4 3   5  4  3 12\n                    16 15 14 13</pre>\n        The input gives you the size of the spiral that you need to create. The goal is to sum the corners. If you\n        look at the 3x3 grid, the numbers at the corners are 7, 9, 3, and 5. If you sum these, you get 24, which is\n        the answer. Write a program that will provide the sum of the corners for any sized spiral up to 100x100.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <p>\n                <span class=\"badge badge-info\">value1</span><br />\n                Single string formatted as ''numberxnumber''.\n            </p>\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Sample Input 1</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 3x3</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 24</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Sample Input 2</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 4x4</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> 46</div>\n        </div>\n    </div>\n</div>\n' where folder = '16_spiral_corner';\nupdate challenges set html = '<div class=\"em_challenge_abstract\">\n    <div class=\"section\">\n        <h4 class=\"f300\">Instructions</h4>\n\n        You''ll get one input string formatted like ''ax^2+bx+c=0''. Return the two decimal values of x like ''x_value1,x_value2''.\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Inputs</h4>\n\n        <div class=\"input\">\n            <p>\n                <span class=\"badge badge-info\">value1</span><br />\n                Single string formatted like ''ax^2+bx+c=0''.\n            </p>\n        </div>\n    </div>\n\n    <div class=\"section\">\n        <h4 class=\"f300\">Sample Test Cases</h4>\n\n        <div class=\"test_case\">\n            <div class=\"f700\">Real</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> -9x^2-9x+7=0</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> -1.51379,-1.51379</div>\n        </div>\n        <div class=\"test_case\">\n            <div class=\"f700\">Imaginary</div>\n            <div class=\"wrap\"><span class=\"badge badge-info\">value1</span> 8x^2-9x+9=0</div>\n            <div class=\"wrap\"><span class=\"badge badge-dark\">output</span> imaginary,imaginary</div>\n        </div>\n    </div>\n</div>\n' where folder = '17_quadratic_calculator';\n\ndown:\nalter table challenges drop column html;\n"
  },
  {
    "path": "platform/migrations/migrations/20210117161957-create-tests-table.sql",
    "content": "up:\ncreate table challenge_tests (\n    challenge_test_id int unsigned not null auto_increment,\n    challenge_id int unsigned not null,\n    official boolean,\n    name varchar(128) not null,\n    input text not null,\n    output text not null,\n    primary key (challenge_test_id),\n    key challenge_id (challenge_id)\n)engine=innodb default charset=utf8;\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (1, false, 'Testing simple string',\n'engineer man\ncat\nreverse me :)\n1234567890a',\n'nam reenigne\ntac\n): em esrever\na0987654321');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (1, false, 'Testing complex string',\n'a,masd#$)(&*09&M0d7fn0s8$*&4876%*&7dnosydhf)\n===================****#$#$\nsd9f6 9s8d6f9 8 s\n78^*&^((((((((((((((()))))))))))))))',\n')fhdysond7&*%6784&*$8s0nf7d0M&90*&()$#dsam,a\n$#$#****===================\ns 8 9f6d8s9 6f9ds\n)))))))))))))))(((((((((((((((^&*^87');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (2, false, 'String of numbers',\n'738923a\n897494889999a\n0004953945000a\n7575847577777a',\n'3\n9\n0\n7');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (3, false, 'Testing short lists',\n'2,5,1\n1,4,5\n-2,4,-9',\n'8\n10\n-7');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (3, false, 'Testing long lists',\n'3,9,10,5,2,7,9,2\n3,32,10,5,2,2,9,12,19,49,6,145\n-3,9,-10,19,-5,-21,9,-4',\n'47\n294\n-6');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (4, false, 'Single Problem',\n'{\"name\":\"em\"\n\"name\":\"somebody\"}\n{\"doggo\":\"chase}\n{\"name\":\"em\" \"doggo\":\"chase\"}',\n'{\"name\":\"em\"}\n{\"name\":\"somebody\"}\n{\"doggo\":\"chase\"}\n{\"name\":\"em\",\"doggo\":\"chase\"}');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (4, false, 'Multiple Problems',\n'\"name\":\"em\n\"doggo\":chase\"\"name\":\"em',\n'{\"name\":\"em\"}\n{\"doggo\":\"chase\",\"name\":\"em\"}');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (5, false, 'Single Problem',\n'abc\nnwv\npdu\nxns\njfj\nnnd',\n'011000010110001001100011\n011011100111011101110110\n011100000110010001110101\n011110000110111001110011\n011010100110011001101010\n011011100110111001100100');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (6, false, 'Testing small numbers',\n'3|2\n8|4\n5|3',\n'5,8\n13,21,34,55\n8,13,21');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (6, false, 'Testing large numbers',\n'34|9\n233|14\n377|6',\n'55,89,144,233,377,610,987,1597,2584\n377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418\n610,987,1597,2584,4181,6765');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (7, false, 'Testing permutations',\n'engineer,gireneen\ncat,act\ne1m2k3c4,e2k3m14c',\n'Yes\nYes\nYes');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (7, false, 'Testing non-permutations',\n'14467,42641\nqwerty,qeerty',\n'No\nNo');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (8, false, 'Testing short lists',\n'2,5,1\n-2,22,-3\n3,4,-9',\n'5,2,1\n22,-2,-3\n4,3,-9');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (8, false, 'Testing long lists',\n'3,9,10,5,2,7,9,2\n3,32,10,5,2,2,9,-5,12,19,49,6,145,-2,-1\n-3,9,-10,19,-5,-21,9,-4',\n'10,9,9,7,5,3,2,2\n145,49,32,19,12,10,9,6,5,3,2,2,-1,-2,-5\n19,9,9,-3,-4,-5,-10,-21');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (9, false, 'Testing small Roman Numerals',\n'VI\nXII\nIII\nI',\n'6\n12\n3\n1');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (9, false, 'Testing large Roman Numerals',\n'CDVII\nCMXCVII\nDCXLIII\nDCCCLXXVI',\n'407\n997\n643\n876');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (10, false, 'Testing small phrases',\n'ig-pay atin-lay\nengineeryay an-may\nave-hay un-fay\nidden-hay essage-may\nilly-say anguage-lay',\n'pig latin\nengineer man\nhave fun\nhidden message\nsilly language');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (10, false, 'Testing large phrases',\n'isyay ift-sway ayay ood-gay anguage-lay\nucks-day areyay etty-pray ool-cay\nis-thay isyay o-say andom-ray at-whay amyay iyay oing-day\nig-pay atin-lay isyay usedyay inyay ools-schay o-tay each-tay anguage-lay onstructs-cay\nityay isyay illy-say ut-bay ort-say ofyay un-fay or-fay ildren-chay',\n'is swift a good language\nducks are pretty cool\nthis is so random what am i doing\npig latin is used in schools to teach language constructs\nit is silly but sort of fun for children');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (11, false, 'Testing short list',\n'1,7,4|6,3,8\n9,2|10,5\n5,3,9|4,8,10\n2,4,6|3,8,10',\n'1,6,7,3,4,8\n9,10,2,5\n5,4,3,8,9,10\n2,3,4,8,6,10');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (11, false, 'Testing long list',\n'1,119,37,17,64,120,24,55,500,255|5,40,21,135,32,110,121,68,300,1000\n279,378,150,800,5,1337,5,8,12,56|6,7,312,10,15,80,385,231,986,1338',\n'1,5,119,40,37,21,17,135,64,32,120,110,24,121,55,68,500,300,255,1000\n279,6,378,7,150,312,800,10,5,15,1337,80,5,385,8,231,12,986,56,1338');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (12, false, 'Regular',\n'run,barn,yellow,barracuda,shark,fish,swim\namerica,united,kingdom,mexico,canada,AUSTRalia\nMeatballs,Noodles,Pizza,Porter,Reuben,Toast,Wine,walnuts,lamb,kale,jerky',\n'barracuda\naustralia\nmeatballs');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (12, false, 'Same Size',\n'fishes,sam,gollum,sauron,frodo,balrog\nrUnNiNg   ,swimming,    eating,biking,   climbing',\n'fishes,gollum,sauron,balrog\nswimming,climbing');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (13, false, 'Testing short strings',\n'Engineer man\nChocolate bar\nWeetabix',\n'n\no,a\ne');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (13, false, 'Testing long strings',\n'tttt::::::tt::t::t:::t:t:\nlllasllsllslsllsllslslslal\nllllttttnabcefghigklmnop',\n':\nl\nl');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (14, false, 'Testing short numbers',\n'3\n17\n57',\n'odd\neven\neven');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (14, false, 'Testing long numbers',\n'74739\n337394\n3739203',\n'even\nodd\nodd');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (15, false, 'Regular Cookie',\n'10101111,10011101111001011010111111110011\n00010100,1011111100010100100000001111100101111111\n10100011,101000111010011100111100',\n'39\n23\n7');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (15, false, 'Big Cookie',\n'011011000110111101101100,101110001111001010100001011110010110110001101111011011000010011000000101\n0110100001101001,1111010000000011011010000110100101101001010100100101110001100001',\n'87\n47');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (16, false, 'Spiral Corner Sum',\n'2x2\n3x3\n4x4\n5x5',\n'10\n24\n46\n76');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (16, false, 'Spiral Corner Sum',\n'24x24\n25x25',\n'2166\n2356');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (17, false, 'Real',\n'1x^2-1x-6=0\nx^2-6x+9=0\n2x^2-6x-7=0\n9x^2-6x-7=0\n9x^2+6x-7=0\n-3x^2+1x+7=0',\n'3,-2\n3,3\n3.89791,-0.89791\n1.27614,-0.60947\n0.60947,-1.27614\n-1.36992,1.70325');\ninsert into challenge_tests (challenge_id, official, name, input, output)\nvalues (17, false, 'Imaginary',\n'2x^2-6x+7=0\n3x^2+1x+7=0\n9x^2+9x+7=0\n-9x^2-9x-7=0',\n'imaginary,imaginary\nimaginary,imaginary\nimaginary,imaginary\nimaginary,imaginary');\n\ndown:\ndrop table challenge_tests;\n"
  },
  {
    "path": "platform/migrations/migrations/20210220201643-piston-run-changes.sql",
    "content": "up:\nalter table piston_runs modify server_id varchar(32) null;\nalter table piston_runs modify user_id varchar(32) null;\n\ndown:\n\nalter table piston_runs modify server_id varchar(32) not null;\nalter table piston_runs modify user_id varchar(32) not null;\n"
  },
  {
    "path": "platform/migrations/migrations/20210314201643-challenge-draft.sql",
    "content": "up:\nalter table challenges add draft tinyint unsigned not null default 1 after challenge_id;\nupdate challenges set draft = 0;\n\ndown:\nalter table challenges drop column draft;\n"
  },
  {
    "path": "platform/migrations/migrations/20210319145442-add-disallowed-languages.sql",
    "content": "up:\nalter table contests add disallowed_languages varchar(2048) after output;\nupdate contests set disallowed_languages = 'python2,awk';\n\ndown:\nalter table contests drop column disallowed_languages;\n"
  },
  {
    "path": "platform/migrations/migrations/20210325110214-change-character-set.sql",
    "content": "up:\nalter table awards convert to character set utf8mb4;\nalter table challenge_tests convert to character set utf8mb4;\nalter table challenges convert to character set utf8mb4;\nalter table cli_scripts convert to character set utf8mb4;\nalter table contest_submissions convert to character set utf8mb4;\nalter table contests convert to character set utf8mb4;\nalter table discord_chat_messages convert to character set utf8mb4;\nalter table piston_runs convert to character set utf8mb4;\nalter table rmig convert to character set utf8mb4;\nalter table snippets convert to character set utf8mb4;\nalter table sticker_orders convert to character set utf8mb4;\nalter table tags convert to character set utf8mb4;\nalter table user_challenges convert to character set utf8mb4;\nalter table users convert to character set utf8mb4;\n\ndown:\nalter table awards convert to character set utf8;\nalter table challenge_tests convert to character set utf8;\nalter table challenges convert to character set utf8;\nalter table cli_scripts convert to character set utf8;\nalter table contest_submissions convert to character set utf8;\nalter table contests convert to character set utf8;\nalter table discord_chat_messages convert to character set utf8;\nalter table piston_runs convert to character set utf8;\nalter table rmig convert to character set utf8;\nalter table snippets convert to character set utf8;\nalter table sticker_orders convert to character set utf8;\nalter table tags convert to character set utf8;\nalter table user_challenges convert to character set utf8;\nalter table users convert to character set utf8;\n"
  },
  {
    "path": "platform/migrations/migrations/20210326154806-add-late-submissions.sql",
    "content": "up:\nalter table contest_submissions add late tinyint unsigned default 0;\n\ndown:\nalter table contest_submissions drop column late;\n"
  },
  {
    "path": "platform/migrations/migrations/20210401114642-add-explanation-field.sql",
    "content": "up:\nalter table contest_submissions add explanation mediumtext not null after length;\n\ndown:\nalter table contest_submissions drop column explanation;\n"
  },
  {
    "path": "platform/migrations/migrations/20210423100104-add-language-version.sql",
    "content": "up:\nalter table contest_submissions add language_version varchar(32) not null after length;\n\ndown:\nalter table contest_submissions drop column language_version;\n"
  },
  {
    "path": "platform/migrations/migrations/20210714100104-add-best-length.sql",
    "content": "up:\nalter table contest_submissions add length_best int unsigned not null after length;\n\ndown:\nalter table contest_submissions drop column length_best;\n"
  },
  {
    "path": "platform/migrations/migrations/20210901095201-remove-contest-draft-field.sql",
    "content": "up:\nalter table contests drop column draft;\n\ndown:\nalter table contests add draft tinyint unsigned not null default 1 after contest_id;\n"
  },
  {
    "path": "platform/migrations/migrations/20220706141314-drop-challenges-folder.sql",
    "content": "up:\nalter table challenges drop column folder;\n\ndown:\nalter table challenges add column folder varchar(64) not null\n"
  },
  {
    "path": "platform/migrations/migrations/20220707092911-drop-official-field.sql",
    "content": "up:\nalter table challenge_tests drop column official;\n\ndown:\nalter table challenge_tests add column official tinyint(1) default null;\n\n"
  },
  {
    "path": "platform/models/awards.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class awards extends Sequelize.Model {}\n\n    awards.init(\n        {\n            award_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            type: DataTypes.INTEGER,\n            points: DataTypes.INTEGER,\n            user_id: DataTypes.INTEGER,\n            ref_type: DataTypes.INTEGER,\n            ref_id: DataTypes.INTEGER,\n            created_at: DataTypes.DATE,\n\n            // getters\n            tooltip_text: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return (\n                        {\n                            [constant.awards.type.contest_first_overall]:\n                                'Placed 1st overall in a contest',\n                            [constant.awards.type.contest_second_overall]:\n                                'Placed 2nd overall in a contest',\n                            [constant.awards.type.contest_third_overall]:\n                                'Placed 3rd overall in a contest',\n                            [constant.awards.type.contest_first_language]:\n                                'Placed 1st for a specific language in a contest',\n                            [constant.awards.type.general_participation]:\n                                'Participation'\n                        }[this.type] || ''\n                    );\n                }\n            }\n        },\n        {\n            sequelize,\n            modelName: 'awards',\n            freezeTableName: true,\n            hooks: {\n                beforeCreate(instance) {\n                    instance.created_at = util.now();\n                }\n            }\n        }\n    );\n\n    return awards;\n};\n"
  },
  {
    "path": "platform/models/challenge_tests.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class challenge_tests extends Sequelize.Model {}\n\n    challenge_tests.init(\n        {\n            challenge_test_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            challenge_id: DataTypes.INTEGER,\n            name: DataTypes.STRING,\n            input: DataTypes.TEXT,\n            output: DataTypes.TEXT\n        },\n        {\n            sequelize,\n            modelName: 'challenge_tests',\n            freezeTableName: true\n        }\n    );\n\n    return challenge_tests;\n};\n"
  },
  {
    "path": "platform/models/challenges.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class challenges extends Sequelize.Model {}\n\n    challenges.init(\n        {\n            challenge_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            draft: DataTypes.INTEGER,\n            difficulty: DataTypes.INTEGER,\n            points: DataTypes.INTEGER,\n            name: DataTypes.STRING,\n            description: DataTypes.STRING,\n            html: DataTypes.TEXT('medium'),\n\n            // getters\n            difficulty_name: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return (\n                        {\n                            [constant.challenges.difficulty.easy]: 'easy',\n                            [constant.challenges.difficulty.medium]: 'medium',\n                            [constant.challenges.difficulty.hard]: 'hard'\n                        }[this.difficulty] || null\n                    );\n                }\n            },\n            difficulty_name_upper: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return (\n                        {\n                            [constant.challenges.difficulty.easy]: 'Easy',\n                            [constant.challenges.difficulty.medium]: 'Medium',\n                            [constant.challenges.difficulty.hard]: 'Hard'\n                        }[this.difficulty] || null\n                    );\n                }\n            }\n        },\n        {\n            sequelize,\n            modelName: 'challenges',\n            freezeTableName: true,\n            hooks: {}\n        }\n    );\n\n    return challenges;\n};\n"
  },
  {
    "path": "platform/models/cli_scripts.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class cli_scripts extends Sequelize.Model {}\n\n    cli_scripts.init(\n        {\n            cli_script_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            user_id: DataTypes.INTEGER,\n            is_public: DataTypes.INTEGER,\n            is_safe: DataTypes.INTEGER,\n            title: DataTypes.STRING,\n            content: DataTypes.TEXT('medium'),\n            created_at: DataTypes.DATE,\n\n            // getters\n            view_url: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return (\n                        '/scripts/' +\n                        this.cli_script_id +\n                        '/' +\n                        util.slugify(this.title)\n                    );\n                }\n            },\n            exec_url: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return '/exec/' + this.cli_script_id;\n                }\n            }\n        },\n        {\n            sequelize,\n            modelName: 'cli_scripts',\n            freezeTableName: true,\n            hooks: {\n                beforeCreate(instance) {\n                    instance.created_at = util.now();\n                }\n            }\n        }\n    );\n\n    return cli_scripts;\n};\n"
  },
  {
    "path": "platform/models/contest_submissions.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class contest_submissions extends Sequelize.Model {}\n\n    contest_submissions.init(\n        {\n            contest_submission_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            user_id: DataTypes.INTEGER,\n            contest_id: DataTypes.INTEGER,\n            language: DataTypes.STRING,\n            language_version: DataTypes.STRING,\n            solution: DataTypes.TEXT('medium'),\n            length: DataTypes.INTEGER,\n            length_best: DataTypes.INTEGER,\n            explanation: DataTypes.TEXT('medium'),\n            award_place: DataTypes.INTEGER,\n            award_points: DataTypes.INTEGER,\n            created_at: DataTypes.DATE,\n            late: DataTypes.INTEGER\n        },\n        {\n            sequelize,\n            modelName: 'contest_submissions',\n            freezeTableName: true,\n            hooks: {\n                beforeCreate(instance) {\n                    instance.created_at = util.now();\n                }\n            }\n        }\n    );\n\n    return contest_submissions;\n};\n"
  },
  {
    "path": "platform/models/contests.js",
    "content": "const Sequelize = require('sequelize');\nconst moment = require('moment');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class contests extends Sequelize.Model {}\n\n    contests.init(\n        {\n            contest_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            name: DataTypes.STRING,\n            description: DataTypes.TEXT('medium'),\n            start_date: DataTypes.DATE,\n            end_date: DataTypes.DATE,\n            input: DataTypes.TEXT,\n            output: DataTypes.TEXT,\n            disallowed_languages: DataTypes.STRING,\n            created_at: DataTypes.DATE,\n\n            // getters\n            active: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return (\n                        moment().isAfter(moment(this.start_date)) &&\n                        moment().isBefore(moment(this.end_date))\n                    );\n                }\n            },\n            url: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return (\n                        '/contests/' +\n                        this.contest_id +\n                        '/' +\n                        util.slugify(this.name)\n                    );\n                }\n            },\n            slug: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return util.slugify(this.name);\n                }\n            },\n            time_left: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    const start = moment().unix();\n                    const end = moment(this.end_date).unix();\n                    const diff = end - start;\n                    const duration = moment.duration(\n                        diff * 1000,\n                        'milliseconds'\n                    );\n\n                    if (duration.weeks() > 0) {\n                        return (\n                            duration.weeks() +\n                            ' week' +\n                            (duration.weeks() == 1 ? '' : 's') +\n                            ' ' +\n                            duration.days() +\n                            ' day' +\n                            (duration.days() == 1 ? '' : 's') +\n                            ' ' +\n                            duration.hours() +\n                            ' hour' +\n                            (duration.hours() == 1 ? '' : 's') +\n                            ' ' +\n                            duration.minutes() +\n                            ' minute' +\n                            (duration.minutes() == 1 ? '' : 's') +\n                            ' '\n                        );\n                    }\n\n                    if (duration.days() > 0) {\n                        return (\n                            duration.days() +\n                            ' day' +\n                            (duration.days() == 1 ? '' : 's') +\n                            ' ' +\n                            duration.hours() +\n                            ' hour' +\n                            (duration.hours() == 1 ? '' : 's') +\n                            ' ' +\n                            duration.minutes() +\n                            ' minute' +\n                            (duration.minutes() == 1 ? '' : 's') +\n                            ' '\n                        );\n                    }\n\n                    if (duration.hours() > 0) {\n                        return (\n                            duration.hours() +\n                            ' hour' +\n                            (duration.hours() == 1 ? '' : 's') +\n                            ' ' +\n                            duration.minutes() +\n                            ' minute' +\n                            (duration.minutes() == 1 ? '' : 's') +\n                            ' '\n                        );\n                    }\n\n                    return (\n                        duration.minutes() +\n                        ' minute' +\n                        (duration.minutes() == 1 ? '' : 's') +\n                        ' '\n                    );\n                }\n            }\n        },\n        {\n            sequelize,\n            modelName: 'contests',\n            freezeTableName: true,\n            hooks: {\n                beforeCreate(instance) {\n                    instance.created_at = util.now();\n                }\n            }\n        }\n    );\n\n    return contests;\n};\n"
  },
  {
    "path": "platform/models/discord_chat_messages.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class discord_chat_messages extends Sequelize.Model {}\n\n    discord_chat_messages.init(\n        {\n            discord_chat_message_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            hash: DataTypes.STRING,\n            channel: DataTypes.STRING,\n            user: DataTypes.STRING,\n            discord_id: DataTypes.STRING,\n            message: DataTypes.STRING,\n            created_at: DataTypes.DATE\n        },\n        {\n            sequelize,\n            modelName: 'discord_chat_messages',\n            freezeTableName: true,\n            hooks: {\n                beforeCreate(instance) {\n                    instance.created_at = util.now();\n                }\n            }\n        }\n    );\n\n    return discord_chat_messages;\n};\n"
  },
  {
    "path": "platform/models/index.js",
    "content": "const path = require('path');\nconst basename = path.basename(module.filename);\nconst config = sails.config.db;\nconst db = {};\n\nconst { Sequelize, DataTypes } = require('sequelize');\nconst sequelize = new Sequelize(\n    config.database,\n    config.username,\n    config.password,\n    config\n);\n\nrequire('fs')\n    .readdir_sync(__dirname)\n    .filter((file) => {\n        return (\n            file.indexOf('.') !== 0 && file !== basename && file.match(/\\.js$/)\n        );\n    })\n    .for_each((file) => {\n        //let model = sequelize.import(path.join(__dirname, file));\n        let model = require(path.join(__dirname, file))(sequelize, DataTypes);\n        db[model.name] = model;\n    });\n\nfor (const model_name in db) {\n    db[model_name].bulk_create = db[model_name].bulkCreate;\n    db[model_name].find_one = db[model_name].findOne;\n    db[model_name].find_all = db[model_name].findAll;\n    db[model_name].find_or_create = db[model_name].findOrCreate;\n    db[model_name].find_and_count_all = db[model_name].findAndCountAll;\n    db[model_name].belongs_to = db[model_name].belongsTo;\n    db[model_name].has_one = db[model_name].hasOne;\n    db[model_name].has_many = db[model_name].hasMany;\n    db[model_name].belongs_to_many = db[model_name].belongsToMany;\n}\n\ndb.sequelize = sequelize;\ndb.Sequelize = Sequelize;\n\n$or = Sequelize.Op.or;\n$and = Sequelize.Op.and;\n$like = Sequelize.Op.like;\n$ne = Sequelize.Op.ne;\n$not = Sequelize.Op.not;\n$gt = Sequelize.Op.gt;\n$gte = Sequelize.Op.gte;\n$lt = Sequelize.Op.lt;\n$lte = Sequelize.Op.lte;\n$in = Sequelize.Op.in;\n$not_in = Sequelize.Op.notIn;\n\ndb.challenges.has_one(db.user_challenges, {\n    as: 'solution',\n    foreignKey: 'challenge_id'\n});\ndb.challenges.has_many(db.user_challenges, {\n    as: 'solutions',\n    foreignKey: 'challenge_id'\n});\ndb.challenges.has_many(db.challenge_tests, {\n    as: 'tests',\n    foreignKey: 'challenge_id'\n});\n\ndb.contests.has_many(db.contest_submissions, {\n    as: 'submissions',\n    foreignKey: 'contest_id'\n});\n\ndb.users.has_many(db.contest_submissions, {\n    as: 'submissions',\n    foreignKey: 'user_id'\n});\n\ndb.user_challenges.belongs_to(db.challenges, {\n    as: 'challenge',\n    foreignKey: 'challenge_id'\n});\ndb.user_challenges.belongs_to(db.users, { as: 'user', foreignKey: 'user_id' });\ndb.challenge_tests.belongs_to(db.challenges, {\n    as: 'challenge',\n    foreignKey: 'challenge_id'\n});\ndb.contest_submissions.belongs_to(db.contests, {\n    as: 'contest',\n    foreignKey: 'contest_id'\n});\ndb.contest_submissions.belongs_to(db.users, {\n    as: 'user',\n    foreignKey: 'user_id'\n});\n\nmodule.exports = db;\n"
  },
  {
    "path": "platform/models/piston_runs.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class piston_runs extends Sequelize.Model {}\n\n    piston_runs.init(\n        {\n            piston_run_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            server: DataTypes.STRING,\n            server_id: DataTypes.STRING,\n            user: DataTypes.STRING,\n            user_id: DataTypes.STRING,\n            language: DataTypes.STRING,\n            source: DataTypes.TEXT,\n            created_at: DataTypes.DATE\n        },\n        {\n            sequelize,\n            modelName: 'piston_runs',\n            freezeTableName: true,\n            hooks: {\n                beforeCreate(instance) {\n                    instance.created_at = util.now();\n                }\n            }\n        }\n    );\n\n    return piston_runs;\n};\n"
  },
  {
    "path": "platform/models/snippets.js",
    "content": "const Sequelize = require('sequelize');\nconst crypto = require('crypto');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class snippets extends Sequelize.Model {}\n\n    snippets.init(\n        {\n            snippet_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            user_id: DataTypes.INTEGER,\n            hash: DataTypes.STRING,\n            language: DataTypes.STRING,\n            snip: DataTypes.TEXT('medium'),\n            created_at: DataTypes.DATE,\n\n            // getters\n            url: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return '/s/' + this.hash;\n                }\n            },\n            time_ago: {\n                type: DataTypes.VIRTUAL,\n                get() {\n                    return util.time_ago(this.created_at);\n                }\n            }\n        },\n        {\n            sequelize,\n            modelName: 'snippets',\n            freezeTableName: true,\n            hooks: {\n                async beforeCreate(instance) {\n                    instance.created_at = util.now();\n\n                    var letters =\n                        'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n\n                    for (;;) {\n                        instance.hash = '';\n                        for (var i = 0; i < 6; ++i) {\n                            instance.hash +=\n                                letters[\n                                    Math.floor(Math.random() * letters.length)\n                                ];\n                        }\n\n                        var dupe = await db.snippets.find_one({\n                            where: {\n                                hash: instance.hash\n                            }\n                        });\n\n                        if (!dupe) break;\n                    }\n                }\n            }\n        }\n    );\n\n    return snippets;\n};\n"
  },
  {
    "path": "platform/models/sticker_orders.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class sticker_orders extends Sequelize.Model {}\n\n    sticker_orders.init(\n        {\n            sticker_order_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            is_fulfilled: DataTypes.INTEGER,\n            tx: DataTypes.STRING,\n            coupon: DataTypes.STRING,\n            quantity: DataTypes.INTEGER,\n            cost: DataTypes.DECIMAL(5, 2),\n            name: DataTypes.STRING,\n            email: DataTypes.STRING,\n            address: DataTypes.TEXT,\n            created_at: DataTypes.DATE\n        },\n        {\n            sequelize,\n            modelName: 'sticker_orders',\n            freezeTableName: true,\n            hooks: {\n                beforeCreate(instance) {\n                    instance.created_at = util.now();\n                }\n            }\n        }\n    );\n\n    return sticker_orders;\n};\n"
  },
  {
    "path": "platform/models/tags.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class tags extends Sequelize.Model {}\n\n    tags.init(\n        {\n            tag_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            name: DataTypes.STRING\n        },\n        {\n            sequelize,\n            modelName: 'tags',\n            freezeTableName: true,\n            hooks: {}\n        }\n    );\n\n    return tags;\n};\n"
  },
  {
    "path": "platform/models/user_challenges.js",
    "content": "const Sequelize = require('sequelize');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class user_challenges extends Sequelize.Model {}\n\n    user_challenges.init(\n        {\n            user_challenge_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            user_id: DataTypes.INTEGER,\n            challenge_id: DataTypes.INTEGER,\n            language: DataTypes.STRING,\n            solution: DataTypes.TEXT('medium'),\n            created_at: DataTypes.DATE\n        },\n        {\n            sequelize,\n            modelName: 'user_challenges',\n            freezeTableName: true,\n            hooks: {\n                beforeCreate(instance) {\n                    instance.created_at = util.now();\n                }\n            }\n        }\n    );\n\n    return user_challenges;\n};\n"
  },
  {
    "path": "platform/models/users.js",
    "content": "const Sequelize = require('sequelize');\nconst crypto = require('crypto');\n\nmodule.exports = (sequelize, DataTypes) => {\n    class users extends Sequelize.Model {}\n\n    users.init(\n        {\n            user_id: {\n                type: DataTypes.INTEGER,\n                primaryKey: true,\n                autoIncrement: true\n            },\n            is_staff: DataTypes.INTEGER,\n            display_name: DataTypes.STRING,\n            username: DataTypes.STRING,\n            email: DataTypes.STRING,\n            password: DataTypes.STRING,\n            discord_api: DataTypes.STRING,\n            discord_rank: DataTypes.INTEGER,\n            avatar_url: DataTypes.STRING,\n            score: DataTypes.INTEGER,\n            created_at: DataTypes.DATE\n        },\n        {\n            sequelize,\n            modelName: 'users',\n            freezeTableName: true,\n            hooks: {\n                beforeCreate(instance) {\n                    instance.created_at = util.now();\n\n                    if (instance.password)\n                        instance.password = crypto\n                            .createHash('sha1')\n                            .update(instance.password)\n                            .digest('hex');\n                },\n\n                beforeUpdate(instance) {\n                    if (instance.changed('password'))\n                        instance.password = crypto\n                            .createHash('sha1')\n                            .update(instance.password)\n                            .digest('hex');\n                }\n            }\n        }\n    );\n\n    return users;\n};\n"
  },
  {
    "path": "platform/package.json",
    "content": "{\n    \"scripts\": {\n        \"prod\": \"run-s prod:webpack prod:app\",\n        \"prod:webpack\": \"webpack --mode production --colors --progress\",\n        \"prod:app\": \"node emkc.js\",\n        \"dev\": \"run-p dev:webpack dev:app\",\n        \"dev:webpack\": \"webpack --mode development --colors --watch --progress\",\n        \"dev:app\": \"nodemon --ignore resources/ --ignore public/ -e js,twig emkc.js\"\n    },\n    \"dependencies\": {\n        \"@babel/core\": \"7.7.4\",\n        \"@babel/plugin-proposal-object-rest-spread\": \"7.7.4\",\n        \"@babel/plugin-proposal-class-properties\": \"7.7.4\",\n        \"@babel/plugin-transform-async-to-generator\": \"7.7.4\",\n        \"@babel/preset-env\": \"7.7.4\",\n        \"@babel/preset-react\": \"7.7.4\",\n        \"@google-cloud/storage\": \"2.0.0\",\n        \"axios\": \"0.19.0\",\n        \"babel-loader\": \"8.0.6\",\n        \"bluebird\": \"3.5.1\",\n        \"connect-redis\": \"3.3.0\",\n        \"core-js\": \"3.6.5\",\n        \"css-loader\": \"3.2.1\",\n        \"file-loader\": \"6.0.0\",\n        \"grunt\": \"0.4.1\",\n        \"ioredis\": \"4.17.3\",\n        \"less\": \"3.10.3\",\n        \"less-loader\": \"5.0.0\",\n        \"lusca\": \"1.3.0\",\n        \"mailgun-js\": \"0.20.0\",\n        \"mini-css-extract-plugin\": \"0.8.0\",\n        \"moment\": \"2.22.2\",\n        \"moment-timezone\": \"0.5.21\",\n        \"monaco-editor\": \"0.20.0\",\n        \"monaco-editor-webpack-plugin\": \"1.9.0\",\n        \"mysql2\": \"2.1.0\",\n        \"nocamel\": \"*\",\n        \"nodemon\": \"2.0.4\",\n        \"npm-run-all\": \"4.1.5\",\n        \"optimist\": \"0.6.1\",\n        \"pm2\": \"4.4.0\",\n        \"q\": \"1.5.0\",\n        \"quill\": \"1.3.7\",\n        \"react\": \"16.12.0\",\n        \"react-dom\": \"16.12.0\",\n        \"react-router\": \"5.1.2\",\n        \"react-router-dom\": \"5.1.2\",\n        \"redis\": \"2.8.0\",\n        \"regenerator-runtime\": \"0.13.3\",\n        \"request-promise\": \"4.2.2\",\n        \"sails\": \"0.12.14\",\n        \"sequelize\": \"6.3.5\",\n        \"socket.io-redis\": \"1.0.0\",\n        \"style-loader\": \"1.0.1\",\n        \"twig\": \"0.8.2\",\n        \"uuid\": \"3.2.1\",\n        \"webpack\": \"^4.41.2\",\n        \"webpack-cli\": \"3.3.10\"\n    }\n}\n"
  },
  {
    "path": "platform/pm2.json",
    "content": "{\n    \"name\": \"emkc\",\n    \"args\": [\"-i 0\"],\n    \"script\": \"emkc.js\",\n    \"node_args\": [\"--max_old_space_size=4096\"],\n    \"error_file\": \"/var/log/emkc.log\",\n    \"out_file\": \"/var/log/emkc.log\",\n    \"instances\": 0,\n    \"merge_logs\": true,\n    \"log_date_format\": \"YYYY-MM-DD HH:mm Z\",\n    \"exec_mode\": \"cluster\"\n}\n"
  },
  {
    "path": "platform/public/css/.gitkeep",
    "content": ""
  },
  {
    "path": "platform/public/js/.gitkeep",
    "content": ""
  },
  {
    "path": "platform/public/lib/bootbox/bootbox.js",
    "content": "/**\n * bootbox.js v4.4.0\n *\n * http://bootboxjs.com/license.txt\n */\n!function(a,b){\"use strict\";\"function\"==typeof define&&define.amd?define([\"jquery\"],b):\"object\"==typeof exports?module.exports=b(require(\"jquery\")):a.bootbox=b(a.jQuery)}(this,function a(b,c){\"use strict\";function d(a){var b=q[o.locale];return b?b[a]:q.en[a]}function e(a,c,d){a.stopPropagation(),a.preventDefault();var e=b.isFunction(d)&&d.call(c,a)===!1;e||c.modal(\"hide\")}function f(a){var b,c=0;for(b in a)c++;return c}function g(a,c){var d=0;b.each(a,function(a,b){c(a,b,d++)})}function h(a){var c,d;if(\"object\"!=typeof a)throw new Error(\"Please supply an object of options\");if(!a.message)throw new Error(\"Please specify a message\");return a=b.extend({},o,a),a.buttons||(a.buttons={}),c=a.buttons,d=f(c),g(c,function(a,e,f){if(b.isFunction(e)&&(e=c[a]={callback:e}),\"object\"!==b.type(e))throw new Error(\"button with key \"+a+\" must be an object\");e.label||(e.label=a),e.className||(e.className=2>=d&&f===d-1?\"btn-primary\":\"btn-default\")}),a}function i(a,b){var c=a.length,d={};if(1>c||c>2)throw new Error(\"Invalid argument length\");return 2===c||\"string\"==typeof a[0]?(d[b[0]]=a[0],d[b[1]]=a[1]):d=a[0],d}function j(a,c,d){return b.extend(!0,{},a,i(c,d))}function k(a,b,c,d){var e={className:\"bootbox-\"+a,buttons:l.apply(null,b)};return m(j(e,d,c),b)}function l(){for(var a={},b=0,c=arguments.length;c>b;b++){var e=arguments[b],f=e.toLowerCase(),g=e.toUpperCase();a[f]={label:d(g)}}return a}function m(a,b){var d={};return g(b,function(a,b){d[b]=!0}),g(a.buttons,function(a){if(d[a]===c)throw new Error(\"button key \"+a+\" is not allowed (options are \"+b.join(\"\\n\")+\")\")}),a}var n={dialog:\"<div class='bootbox modal' tabindex='-1' role='dialog'><div class='modal-dialog'><div class='modal-content'><div class='modal-body'><div class='bootbox-body'></div></div></div></div></div>\",header:\"<div class='modal-header'><h4 class='modal-title'></h4></div>\",footer:\"<div class='modal-footer'></div>\",closeButton:\"<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>&times;</button>\",form:\"<form class='bootbox-form'></form>\",inputs:{text:\"<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />\",textarea:\"<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>\",email:\"<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />\",select:\"<select class='bootbox-input bootbox-input-select form-control'></select>\",checkbox:\"<div class='checkbox'><label><input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>\",date:\"<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />\",time:\"<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />\",number:\"<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />\",password:\"<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />\"}},o={locale:\"en\",backdrop:\"static\",animate:!0,className:null,closeButton:!0,show:!0,container:\"body\"},p={};p.alert=function(){var a;if(a=k(\"alert\",[\"ok\"],[\"message\",\"callback\"],arguments),a.callback&&!b.isFunction(a.callback))throw new Error(\"alert requires callback property to be a function when provided\");return a.buttons.ok.callback=a.onEscape=function(){return b.isFunction(a.callback)?a.callback.call(this):!0},p.dialog(a)},p.confirm=function(){var a;if(a=k(\"confirm\",[\"cancel\",\"confirm\"],[\"message\",\"callback\"],arguments),a.buttons.cancel.callback=a.onEscape=function(){return a.callback.call(this,!1)},a.buttons.confirm.callback=function(){return a.callback.call(this,!0)},!b.isFunction(a.callback))throw new Error(\"confirm requires a callback\");return p.dialog(a)},p.prompt=function(){var a,d,e,f,h,i,k;if(f=b(n.form),d={className:\"bootbox-prompt\",buttons:l(\"cancel\",\"confirm\"),value:\"\",inputType:\"text\"},a=m(j(d,arguments,[\"title\",\"callback\"]),[\"cancel\",\"confirm\"]),i=a.show===c?!0:a.show,a.message=f,a.buttons.cancel.callback=a.onEscape=function(){return a.callback.call(this,null)},a.buttons.confirm.callback=function(){var c;switch(a.inputType){case\"text\":case\"textarea\":case\"email\":case\"select\":case\"date\":case\"time\":case\"number\":case\"password\":c=h.val();break;case\"checkbox\":var d=h.find(\"input:checked\");c=[],g(d,function(a,d){c.push(b(d).val())})}return a.callback.call(this,c)},a.show=!1,!a.title)throw new Error(\"prompt requires a title\");if(!b.isFunction(a.callback))throw new Error(\"prompt requires a callback\");if(!n.inputs[a.inputType])throw new Error(\"invalid prompt type\");switch(h=b(n.inputs[a.inputType]),a.inputType){case\"text\":case\"textarea\":case\"email\":case\"date\":case\"time\":case\"number\":case\"password\":h.val(a.value);break;case\"select\":var o={};if(k=a.inputOptions||[],!b.isArray(k))throw new Error(\"Please pass an array of input options\");if(!k.length)throw new Error(\"prompt with select requires options\");g(k,function(a,d){var e=h;if(d.value===c||d.text===c)throw new Error(\"given options in wrong format\");d.group&&(o[d.group]||(o[d.group]=b(\"<optgroup/>\").attr(\"label\",d.group)),e=o[d.group]),e.append(\"<option value='\"+d.value+\"'>\"+d.text+\"</option>\")}),g(o,function(a,b){h.append(b)}),h.val(a.value);break;case\"checkbox\":var q=b.isArray(a.value)?a.value:[a.value];if(k=a.inputOptions||[],!k.length)throw new Error(\"prompt with checkbox requires options\");if(!k[0].value||!k[0].text)throw new Error(\"given options in wrong format\");h=b(\"<div/>\"),g(k,function(c,d){var e=b(n.inputs[a.inputType]);e.find(\"input\").attr(\"value\",d.value),e.find(\"label\").append(d.text),g(q,function(a,b){b===d.value&&e.find(\"input\").prop(\"checked\",!0)}),h.append(e)})}return a.placeholder&&h.attr(\"placeholder\",a.placeholder),a.pattern&&h.attr(\"pattern\",a.pattern),a.maxlength&&h.attr(\"maxlength\",a.maxlength),f.append(h),f.on(\"submit\",function(a){a.preventDefault(),a.stopPropagation(),e.find(\".btn-primary\").click()}),e=p.dialog(a),e.off(\"shown.bs.modal\"),e.on(\"shown.bs.modal\",function(){h.focus()}),i===!0&&e.modal(\"show\"),e},p.dialog=function(a){a=h(a);var d=b(n.dialog),f=d.find(\".modal-dialog\"),i=d.find(\".modal-body\"),j=a.buttons,k=\"\",l={onEscape:a.onEscape};if(b.fn.modal===c)throw new Error(\"$.fn.modal is not defined; please double check you have included the Bootstrap JavaScript library. See http://getbootstrap.com/javascript/ for more details.\");if(g(j,function(a,b){k+=\"<button data-bb-handler='\"+a+\"' type='button' class='btn \"+b.className+\"'>\"+b.label+\"</button>\",l[a]=b.callback}),i.find(\".bootbox-body\").html(a.message),a.animate===!0&&d.addClass(\"fade\"),a.className&&d.addClass(a.className),\"large\"===a.size?f.addClass(\"modal-lg\"):\"small\"===a.size&&f.addClass(\"modal-sm\"),a.title&&i.before(n.header),a.closeButton){var m=b(n.closeButton);a.title?d.find(\".modal-header\").prepend(m):m.css(\"margin-top\",\"-10px\").prependTo(i)}return a.title&&d.find(\".modal-title\").html(a.title),k.length&&(i.after(n.footer),d.find(\".modal-footer\").html(k)),d.on(\"hidden.bs.modal\",function(a){a.target===this&&d.remove()}),d.on(\"shown.bs.modal\",function(){d.find(\".btn-primary:first\").focus()}),\"static\"!==a.backdrop&&d.on(\"click.dismiss.bs.modal\",function(a){d.children(\".modal-backdrop\").length&&(a.currentTarget=d.children(\".modal-backdrop\").get(0)),a.target===a.currentTarget&&d.trigger(\"escape.close.bb\")}),d.on(\"escape.close.bb\",function(a){l.onEscape&&e(a,d,l.onEscape)}),d.on(\"click\",\".modal-footer button\",function(a){var c=b(this).data(\"bb-handler\");e(a,d,l[c])}),d.on(\"click\",\".bootbox-close-button\",function(a){e(a,d,l.onEscape)}),d.on(\"keyup\",function(a){27===a.which&&d.trigger(\"escape.close.bb\")}),b(a.container).append(d),d.modal({backdrop:a.backdrop?\"static\":!1,keyboard:!1,show:!1}),a.show&&d.modal(\"show\"),d},p.setDefaults=function(){var a={};2===arguments.length?a[arguments[0]]=arguments[1]:a=arguments[0],b.extend(o,a)},p.hideAll=function(){return b(\".bootbox\").modal(\"hide\"),p};var q={bg_BG:{OK:\"Ок\",CANCEL:\"Отказ\",CONFIRM:\"Потвърждавам\"},br:{OK:\"OK\",CANCEL:\"Cancelar\",CONFIRM:\"Sim\"},cs:{OK:\"OK\",CANCEL:\"Zrušit\",CONFIRM:\"Potvrdit\"},da:{OK:\"OK\",CANCEL:\"Annuller\",CONFIRM:\"Accepter\"},de:{OK:\"OK\",CANCEL:\"Abbrechen\",CONFIRM:\"Akzeptieren\"},el:{OK:\"Εντάξει\",CANCEL:\"Ακύρωση\",CONFIRM:\"Επιβεβαίωση\"},en:{OK:\"OK\",CANCEL:\"Cancel\",CONFIRM:\"OK\"},es:{OK:\"OK\",CANCEL:\"Cancelar\",CONFIRM:\"Aceptar\"},et:{OK:\"OK\",CANCEL:\"Katkesta\",CONFIRM:\"OK\"},fa:{OK:\"قبول\",CANCEL:\"لغو\",CONFIRM:\"تایید\"},fi:{OK:\"OK\",CANCEL:\"Peruuta\",CONFIRM:\"OK\"},fr:{OK:\"OK\",CANCEL:\"Annuler\",CONFIRM:\"D'accord\"},he:{OK:\"אישור\",CANCEL:\"ביטול\",CONFIRM:\"אישור\"},hu:{OK:\"OK\",CANCEL:\"Mégsem\",CONFIRM:\"Megerősít\"},hr:{OK:\"OK\",CANCEL:\"Odustani\",CONFIRM:\"Potvrdi\"},id:{OK:\"OK\",CANCEL:\"Batal\",CONFIRM:\"OK\"},it:{OK:\"OK\",CANCEL:\"Annulla\",CONFIRM:\"Conferma\"},ja:{OK:\"OK\",CANCEL:\"キャンセル\",CONFIRM:\"確認\"},lt:{OK:\"Gerai\",CANCEL:\"Atšaukti\",CONFIRM:\"Patvirtinti\"},lv:{OK:\"Labi\",CANCEL:\"Atcelt\",CONFIRM:\"Apstiprināt\"},nl:{OK:\"OK\",CANCEL:\"Annuleren\",CONFIRM:\"Accepteren\"},no:{OK:\"OK\",CANCEL:\"Avbryt\",CONFIRM:\"OK\"},pl:{OK:\"OK\",CANCEL:\"Anuluj\",CONFIRM:\"Potwierdź\"},pt:{OK:\"OK\",CANCEL:\"Cancelar\",CONFIRM:\"Confirmar\"},ru:{OK:\"OK\",CANCEL:\"Отмена\",CONFIRM:\"Применить\"},sq:{OK:\"OK\",CANCEL:\"Anulo\",CONFIRM:\"Prano\"},sv:{OK:\"OK\",CANCEL:\"Avbryt\",CONFIRM:\"OK\"},th:{OK:\"ตกลง\",CANCEL:\"ยกเลิก\",CONFIRM:\"ยืนยัน\"},tr:{OK:\"Tamam\",CANCEL:\"İptal\",CONFIRM:\"Onayla\"},zh_CN:{OK:\"OK\",CANCEL:\"取消\",CONFIRM:\"确认\"},zh_TW:{OK:\"OK\",CANCEL:\"取消\",CONFIRM:\"確認\"}};return p.addLocale=function(a,c){return b.each([\"OK\",\"CANCEL\",\"CONFIRM\"],function(a,b){if(!c[b])throw new Error(\"Please supply a translation for '\"+b+\"'\")}),q[a]={OK:c.OK,CANCEL:c.CANCEL,CONFIRM:c.CONFIRM},p},p.removeLocale=function(a){return delete q[a],p},p.setLocale=function(a){return p.setDefaults(\"locale\",a)},p.init=function(c){return a(c||b)},p});\n"
  },
  {
    "path": "platform/public/lib/highlightjs/atom-one-dark.css",
    "content": "/*\n\nAtom One Dark by Daniel Gamage\nOriginal One Dark Syntax theme from https://github.com/atom/one-dark-syntax\n\nbase:    #282c34\nmono-1:  #abb2bf\nmono-2:  #818896\nmono-3:  #5c6370\nhue-1:   #56b6c2\nhue-2:   #61aeee\nhue-3:   #c678dd\nhue-4:   #98c379\nhue-5:   #e06c75\nhue-5-2: #be5046\nhue-6:   #d19a66\nhue-6-2: #e6c07b\n\n*/\n\n.hljs {\n  display: block;\n  overflow-x: auto;\n  padding: 0.5em;\n  color: #abb2bf;\n  background: #24282F !important;\n}\n\n.hljs-comment,\n.hljs-quote {\n  color: #5c6370;\n  font-style: italic;\n}\n\n.hljs-doctag,\n.hljs-keyword,\n.hljs-formula {\n  color: #c678dd;\n}\n\n.hljs-section,\n.hljs-name,\n.hljs-selector-tag,\n.hljs-deletion,\n.hljs-subst {\n  color: #e06c75;\n}\n\n.hljs-literal {\n  color: #56b6c2;\n}\n\n.hljs-string,\n.hljs-regexp,\n.hljs-addition,\n.hljs-attribute,\n.hljs-meta-string {\n  color: #98c379;\n}\n\n.hljs-built_in,\n.hljs-class .hljs-title {\n  color: #e6c07b;\n}\n\n.hljs-attr,\n.hljs-variable,\n.hljs-template-variable,\n.hljs-type,\n.hljs-selector-class,\n.hljs-selector-attr,\n.hljs-selector-pseudo,\n.hljs-number {\n  color: #d19a66;\n}\n\n.hljs-symbol,\n.hljs-bullet,\n.hljs-link,\n.hljs-meta,\n.hljs-selector-id,\n.hljs-title {\n  color: #61aeee;\n}\n\n.hljs-emphasis {\n  font-style: italic;\n}\n\n.hljs-strong {\n  font-weight: bold;\n}\n\n.hljs-link {\n  text-decoration: underline;\n}\n"
  },
  {
    "path": "platform/public/lib/highlightjs/default.css",
    "content": "/*\n\nOriginal highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>\n\n*/\n\n.hljs {\n  display: block;\n  overflow-x: auto;\n  padding: 0.5em;\n  background: #F0F0F0;\n}\n\n\n/* Base color: saturation 0; */\n\n.hljs,\n.hljs-subst {\n  color: #444;\n}\n\n.hljs-comment {\n  color: #888888;\n}\n\n.hljs-keyword,\n.hljs-attribute,\n.hljs-selector-tag,\n.hljs-meta-keyword,\n.hljs-doctag,\n.hljs-name {\n  font-weight: bold;\n}\n\n\n/* User color: hue: 0 */\n\n.hljs-type,\n.hljs-string,\n.hljs-number,\n.hljs-selector-id,\n.hljs-selector-class,\n.hljs-quote,\n.hljs-template-tag,\n.hljs-deletion {\n  color: #880000;\n}\n\n.hljs-title,\n.hljs-section {\n  color: #880000;\n  font-weight: bold;\n}\n\n.hljs-regexp,\n.hljs-symbol,\n.hljs-variable,\n.hljs-template-variable,\n.hljs-link,\n.hljs-selector-attr,\n.hljs-selector-pseudo {\n  color: #BC6060;\n}\n\n\n/* Language color: hue: 90; */\n\n.hljs-literal {\n  color: #78A960;\n}\n\n.hljs-built_in,\n.hljs-bullet,\n.hljs-code,\n.hljs-addition {\n  color: #397300;\n}\n\n\n/* Meta color: hue: 200 */\n\n.hljs-meta {\n  color: #1f7199;\n}\n\n.hljs-meta-string {\n  color: #4d99bf;\n}\n\n\n/* Misc effects */\n\n.hljs-emphasis {\n  font-style: italic;\n}\n\n.hljs-strong {\n  font-weight: bold;\n}\n"
  },
  {
    "path": "platform/public/lib/highlightjs/highlight-ln.js",
    "content": "!function(n,e){\"use strict\";function t(){var n=e.createElement(\"style\");n.type=\"text/css\",n.innerHTML=h(\".{0}{border-collapse:collapse}.{0} td{padding:0}.{1}:before{content:attr({2})}\",[f,m,j]),e.getElementsByTagName(\"head\")[0].appendChild(n)}function r(t){\"complete\"===e.readyState?l(t):n.addEventListener(\"DOMContentLoaded\",function(){l(t)})}function l(t){try{var r=e.querySelectorAll(\"code.hljs\");for(var l in r)r.hasOwnProperty(l)&&i(r[l],t)}catch(o){n.console.error(\"LineNumbers error: \",o)}}function i(n,e){if(\"object\"==typeof n){e=e||{singleLine:!1};var t=e.singleLine?0:1;u(function(){s(n),n.innerHTML=o(n.innerHTML,t)})}}function o(n,e){var t=c(n);if(\"\"===t[t.length-1].trim()&&t.pop(),t.length>e){for(var r=\"\",l=0,i=t.length;l<i;l++)r+=h('<tr><td class=\"{0}\"><div class=\"{1} {2}\" {3}=\"{5}\"></div></td><td class=\"{4}\"><div class=\"{1}\">{6}</div></td></tr>',[v,g,m,j,p,l+1,t[l].length>0?t[l]:\" \"]);return h('<table class=\"{0}\">{1}</table>',[f,r])}return n}function s(n){var e=n.childNodes;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];d(r.textContent)>0&&(r.childNodes.length>0?s(r):a(r.parentNode))}}function a(n){var e=n.className;if(/hljs-/.test(e)){for(var t=c(n.innerHTML),r=0,l=\"\";r<t.length;r++)l+=h('<span class=\"{0}\">{1}</span>\\n',[e,t[r]]);n.innerHTML=l.trim()}}function c(n){return 0===n.length?[]:n.split(L)}function d(n){return(n.trim().match(L)||[]).length}function u(e){n.setTimeout(e,0)}function h(n,e){return n.replace(/\\{(\\d+)\\}/g,function(n,t){return e[t]?e[t]:n})}var f=\"hljs-ln\",g=\"hljs-ln-line\",p=\"hljs-ln-code\",v=\"hljs-ln-numbers\",m=\"hljs-ln-n\",j=\"data-line-number\",L=/\\r\\n|\\r|\\n/g;n.hljs?(n.hljs.initLineNumbersOnLoad=r,n.hljs.lineNumbersBlock=i,t()):n.console.error(\"highlight.js not detected!\")}(window,document);\n"
  },
  {
    "path": "platform/public/lib/highlightjs/highlight.pack.js",
    "content": "/*! highlight.js v9.12.0 | BSD3 License | git.io/hljslicense */\n!function(e){var n=\"object\"==typeof window&&window||\"object\"==typeof self&&self;\"undefined\"!=typeof exports?e(exports):n&&(n.hljs=e({}),\"function\"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+\" \";if(o+=e.parentNode?e.parentNode.className:\"\",t=B.exec(o))return w(t[1])?t[1]:\"no-highlight\";for(o=o.split(/\\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:\"start\",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:\"stop\",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset<r[0].offset?e:r:\"start\"===r[0].event?e:r:e.length?e:r}function o(e){function r(e){return\" \"+e.nodeName+'=\"'+n(e.value).replace('\"',\"&quot;\")+'\"'}s+=\"<\"+t(e)+E.map.call(e.attributes,r).join(\"\")+\">\"}function u(e){s+=\"</\"+t(e)+\">\"}function c(e){(\"start\"===e.event?o:u)(e.node)}for(var l=0,s=\"\",f=[];e.length||r.length;){var g=i();if(s+=n(a.substring(l,g[0].offset)),l=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===l);f.reverse().forEach(o)}else\"start\"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return s+n(a.substr(l))}function l(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),\"m\"+(e.cI?\"i\":\"\")+(r?\"g\":\"\"))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},u=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(\" \").forEach(function(e){var t=e.split(\"|\");o[t[0]]=[n,t[1]?Number(t[1]):1]})};\"string\"==typeof a.k?u(\"keyword\",a.k):x(a.k).forEach(function(e){u(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\\w+/,!0),i&&(a.bK&&(a.b=\"\\\\b(\"+a.bK.split(\" \").join(\"|\")+\")\\\\b\"),a.b||(a.b=/\\B|\\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\\B|\\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||\"\",a.eW&&i.tE&&(a.tE+=(a.e?\"|\":\"\")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return l(\"self\"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var c=a.c.map(function(e){return e.bK?\"\\\\.?(\"+e.b+\")\\\\.?\":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=c.length?t(c.join(\"|\"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function l(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?\"\":I.classPrefix,i='<span class=\"'+a,o=t?\"\":C;return i+=e+'\">',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a=\"\",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=l(E,r),e?(B+=e[1],a+=p(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function d(){var e=\"string\"==typeof E.sL;if(e&&!y[E.sL])return n(k);var t=e?f(E.sL,k,!0,x[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(B+=t.r),e&&(x[E.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=null!=E.sL?d():h(),k=\"\"}function v(e){L+=e.cN?p(e.cN,\"\",!0):\"\",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(k+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),b(),t.rB||t.eB||(k=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),b(),a.eE&&(k=n));do E.cN&&(L+=C),E.skip||(B+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,\"\"),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme \"'+n+'\" for mode \"'+(E.cN||\"<unnamed>\")+'\"');return k+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: \"'+e+'\"');s(N);var R,E=i||N,x={},L=\"\";for(R=E;R!==N;R=R.parent)R.cN&&(L=p(R.cN,\"\",!0)+L);var k=\"\",B=0;try{for(var M,j,O=0;;){if(E.t.lastIndex=O,M=E.t.exec(t),!M)break;j=m(t.substring(O,M.index),M[0]),O=M.index+j}for(m(t.substr(O)),R=E;R.parent;R=R.parent)R.cN&&(L+=C);return{r:B,value:L,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf(\"Illegal\"))return{r:0,value:n(t)};throw T}}function g(e,t){t=t||I.languages||x(y);var r={r:0,value:n(e)},a=r;return t.filter(w).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return I.tabReplace||I.useBR?e.replace(M,function(e,n){return I.useBR&&\"\\n\"===e?\"<br>\":I.tabReplace?n.replace(/\\t/g,I.tabReplace):\"\"}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\\bhljs\\b/)||a.push(\"hljs\"),-1===e.indexOf(r)&&a.push(r),a.join(\" \").trim()}function d(e){var n,t,r,o,l,s=i(e);a(s)||(I.useBR?(n=document.createElementNS(\"http://www.w3.org/1999/xhtml\",\"div\"),n.innerHTML=e.innerHTML.replace(/\\n/g,\"\").replace(/<br[ \\/]*>/g,\"\\n\")):n=e,l=n.textContent,r=s?f(s,l,!0):g(l),t=u(n),t.length&&(o=document.createElementNS(\"http://www.w3.org/1999/xhtml\",\"div\"),o.innerHTML=r.value,r.value=c(t,u(o),l)),r.value=p(r.value),e.innerHTML=r.value,e.className=h(e.className,s,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){I=o(I,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll(\"pre code\");E.forEach.call(e,d)}}function m(){addEventListener(\"DOMContentLoaded\",v,!1),addEventListener(\"load\",v,!1)}function N(n,t){var r=y[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function R(){return x(y)}function w(e){return e=(e||\"\").toLowerCase(),y[e]||y[L[e]]}var E=[],x=Object.keys,y={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\\blang(?:uage)?-([\\w-]+)\\b/i,M=/((^(<[^>]+>|\\t|)+|(?:\\n)))/gm,C=\"</span>\",I={classPrefix:\"hljs-\",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=d,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.inherit=o,e.IR=\"[a-zA-Z]\\\\w*\",e.UIR=\"[a-zA-Z_]\\\\w*\",e.NR=\"\\\\b\\\\d+(\\\\.\\\\d+)?\",e.CNR=\"(-?)(\\\\b0[xX][a-fA-F0-9]+|(\\\\b\\\\d+(\\\\.\\\\d*)?|\\\\.\\\\d+)([eE][-+]?\\\\d+)?)\",e.BNR=\"\\\\b(0b[01]+)\",e.RSR=\"!|!=|!==|%|%=|&|&&|&=|\\\\*|\\\\*=|\\\\+|\\\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\\\?|\\\\[|\\\\{|\\\\(|\\\\^|\\\\^=|\\\\||\\\\|=|\\\\|\\\\||~\",e.BE={b:\"\\\\\\\\[\\\\s\\\\S]\",r:0},e.ASM={cN:\"string\",b:\"'\",e:\"'\",i:\"\\\\n\",c:[e.BE]},e.QSM={cN:\"string\",b:'\"',e:'\"',i:\"\\\\n\",c:[e.BE]},e.PWM={b:/\\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\\b/},e.C=function(n,t,r){var a=e.inherit({cN:\"comment\",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:\"doctag\",b:\"(?:TODO|FIXME|NOTE|BUG|XXX):\",r:0}),a},e.CLCM=e.C(\"//\",\"$\"),e.CBCM=e.C(\"/\\\\*\",\"\\\\*/\"),e.HCM=e.C(\"#\",\"$\"),e.NM={cN:\"number\",b:e.NR,r:0},e.CNM={cN:\"number\",b:e.CNR,r:0},e.BNM={cN:\"number\",b:e.BNR,r:0},e.CSSNM={cN:\"number\",b:e.NR+\"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?\",r:0},e.RM={cN:\"regexp\",b:/\\//,e:/\\/[gimuy]*/,i:/\\n/,c:[e.BE,{b:/\\[/,e:/\\]/,r:0,c:[e.BE]}]},e.TM={cN:\"title\",b:e.IR,r:0},e.UTM={cN:\"title\",b:e.UIR,r:0},e.METHOD_GUARD={b:\"\\\\.\\\\s*\"+e.UIR,r:0},e});hljs.registerLanguage(\"xml\",function(s){var e=\"[A-Za-z0-9\\\\._:-]+\",t={eW:!0,i:/</,r:0,c:[{cN:\"attr\",b:e,r:0},{b:/=\\s*/,r:0,c:[{cN:\"string\",endsParent:!0,v:[{b:/\"/,e:/\"/},{b:/'/,e:/'/},{b:/[^\\s\"'=<>`]+/}]}]}]};return{aliases:[\"html\",\"xhtml\",\"rss\",\"atom\",\"xjb\",\"xsd\",\"xsl\",\"plist\"],cI:!0,c:[{cN:\"meta\",b:\"<!DOCTYPE\",e:\">\",r:10,c:[{b:\"\\\\[\",e:\"\\\\]\"}]},s.C(\"<!--\",\"-->\",{r:10}),{b:\"<\\\\!\\\\[CDATA\\\\[\",e:\"\\\\]\\\\]>\",r:10},{b:/<\\?(php)?/,e:/\\?>/,sL:\"php\",c:[{b:\"/\\\\*\",e:\"\\\\*/\",skip:!0}]},{cN:\"tag\",b:\"<style(?=\\\\s|>|$)\",e:\">\",k:{name:\"style\"},c:[t],starts:{e:\"</style>\",rE:!0,sL:[\"css\",\"xml\"]}},{cN:\"tag\",b:\"<script(?=\\\\s|>|$)\",e:\">\",k:{name:\"script\"},c:[t],starts:{e:\"</script>\",rE:!0,sL:[\"actionscript\",\"javascript\",\"handlebars\",\"xml\"]}},{cN:\"meta\",v:[{b:/<\\?xml/,e:/\\?>/,r:10},{b:/<\\?\\w+/,e:/\\?>/}]},{cN:\"tag\",b:\"</?\",e:\"/?>\",c:[{cN:\"name\",b:/[^\\/><\\s]+/,r:0},t]}]}});hljs.registerLanguage(\"markdown\",function(e){return{aliases:[\"md\",\"mkdown\",\"mkd\"],c:[{cN:\"section\",v:[{b:\"^#{1,6}\",e:\"$\"},{b:\"^.+?\\\\n[=-]{2,}$\"}]},{b:\"<\",e:\">\",sL:\"xml\",r:0},{cN:\"bullet\",b:\"^([*+-]|(\\\\d+\\\\.))\\\\s+\"},{cN:\"strong\",b:\"[*_]{2}.+?[*_]{2}\"},{cN:\"emphasis\",v:[{b:\"\\\\*.+?\\\\*\"},{b:\"_.+?_\",r:0}]},{cN:\"quote\",b:\"^>\\\\s+\",e:\"$\"},{cN:\"code\",v:[{b:\"^```w*s*$\",e:\"^```s*$\"},{b:\"`.+?`\"},{b:\"^( {4}|\t)\",e:\"$\",r:0}]},{b:\"^[-\\\\*]{3,}\",e:\"$\"},{b:\"\\\\[.+?\\\\][\\\\(\\\\[].*?[\\\\)\\\\]]\",rB:!0,c:[{cN:\"string\",b:\"\\\\[\",e:\"\\\\]\",eB:!0,rE:!0,r:0},{cN:\"link\",b:\"\\\\]\\\\(\",e:\"\\\\)\",eB:!0,eE:!0},{cN:\"symbol\",b:\"\\\\]\\\\[\",e:\"\\\\]\",eB:!0,eE:!0}],r:10},{b:/^\\[[^\\n]+\\]:/,rB:!0,c:[{cN:\"symbol\",b:/\\[/,e:/\\]/,eB:!0,eE:!0},{cN:\"link\",b:/:\\s*/,e:/$/,eB:!0}]}]}});hljs.registerLanguage(\"javascript\",function(e){var r=\"[A-Za-z$_][0-9A-Za-z$_]*\",t={keyword:\"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as\",literal:\"true false null undefined NaN Infinity\",built_in:\"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise\"},a={cN:\"number\",v:[{b:\"\\\\b(0[bB][01]+)\"},{b:\"\\\\b(0[oO][0-7]+)\"},{b:e.CNR}],r:0},n={cN:\"subst\",b:\"\\\\$\\\\{\",e:\"\\\\}\",k:t,c:[]},c={cN:\"string\",b:\"`\",e:\"`\",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:[\"js\",\"jsx\"],k:t,c:[{cN:\"meta\",r:10,b:/^\\s*['\"]use (strict|asm)['\"]/},{cN:\"meta\",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\\s*/,r:0,c:[{b:r+\"\\\\s*:\",rB:!0,r:0,c:[{cN:\"attr\",b:r,r:0}]}]},{b:\"(\"+e.RSR+\"|\\\\b(case|return|throw)\\\\b)\\\\s*\",k:\"return throw case\",c:[e.CLCM,e.CBCM,e.RM,{cN:\"function\",b:\"(\\\\(.*?\\\\)|\"+r+\")\\\\s*=>\",rB:!0,e:\"\\\\s*=>\",c:[{cN:\"params\",v:[{b:r},{b:/\\(\\s*\\)/},{b:/\\(/,e:/\\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b:/</,e:/(\\/\\w+|\\w+\\/)>/,sL:\"xml\",c:[{b:/<\\w+\\s*\\/>/,skip:!0},{b:/<\\w+/,e:/(\\/\\w+|\\w+\\/)>/,skip:!0,c:[{b:/<\\w+\\s*\\/>/,skip:!0},\"self\"]}]}],r:0},{cN:\"function\",bK:\"function\",e:/\\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:\"params\",b:/\\(/,e:/\\)/,eB:!0,eE:!0,c:s}],i:/\\[|%/},{b:/\\$[(.]/},e.METHOD_GUARD,{cN:\"class\",bK:\"class\",e:/[{;=]/,eE:!0,i:/[:\"\\[\\]]/,c:[{bK:\"extends\"},e.UTM]},{bK:\"constructor\",e:/\\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage(\"diff\",function(e){return{aliases:[\"patch\"],c:[{cN:\"meta\",r:10,v:[{b:/^@@ +\\-\\d+,\\d+ +\\+\\d+,\\d+ +@@$/},{b:/^\\*\\*\\* +\\d+,\\d+ +\\*\\*\\*\\*$/},{b:/^\\-\\-\\- +\\d+,\\d+ +\\-\\-\\-\\-$/}]},{cN:\"comment\",v:[{b:/Index: /,e:/$/},{b:/={3,}/,e:/$/},{b:/^\\-{3}/,e:/$/},{b:/^\\*{3} /,e:/$/},{b:/^\\+{3}/,e:/$/},{b:/\\*{5}/,e:/\\*{5}$/}]},{cN:\"addition\",b:\"^\\\\+\",e:\"$\"},{cN:\"deletion\",b:\"^\\\\-\",e:\"$\"},{cN:\"addition\",b:\"^\\\\!\",e:\"$\"}]}});hljs.registerLanguage(\"nginx\",function(e){var r={cN:\"variable\",v:[{b:/\\$\\d+/},{b:/\\$\\{/,e:/}/},{b:\"[\\\\$\\\\@]\"+e.UIR}]},b={eW:!0,l:\"[a-z/_]+\",k:{literal:\"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll\"},r:0,i:\"=>\",c:[e.HCM,{cN:\"string\",c:[e.BE,r],v:[{b:/\"/,e:/\"/},{b:/'/,e:/'/}]},{b:\"([a-z]+):/\",e:\"\\\\s\",eW:!0,eE:!0,c:[r]},{cN:\"regexp\",c:[e.BE,r],v:[{b:\"\\\\s\\\\^\",e:\"\\\\s|{|;\",rE:!0},{b:\"~\\\\*?\\\\s+\",e:\"\\\\s|{|;\",rE:!0},{b:\"\\\\*(\\\\.[a-z\\\\-]+)+\"},{b:\"([a-z\\\\-]+\\\\.)+\\\\*\"}]},{cN:\"number\",b:\"\\\\b\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}(:\\\\d{1,5})?\\\\b\"},{cN:\"number\",b:\"\\\\b\\\\d+[kKmMgGdshdwy]*\\\\b\",r:0},r]};return{aliases:[\"nginxconf\"],c:[e.HCM,{b:e.UIR+\"\\\\s+{\",rB:!0,e:\"{\",c:[{cN:\"section\",b:e.UIR}],r:0},{b:e.UIR+\"\\\\s\",e:\";|{\",rB:!0,c:[{cN:\"attribute\",b:e.UIR,starts:b}],r:0}],i:\"[^\\\\s\\\\}]\"}});hljs.registerLanguage(\"bash\",function(e){var t={cN:\"variable\",v:[{b:/\\$[\\w\\d#@][\\w\\d_]*/},{b:/\\$\\{(.*?)}/}]},s={cN:\"string\",b:/\"/,e:/\"/,c:[e.BE,t,{cN:\"variable\",b:/\\$\\(/,e:/\\)/,c:[e.BE]}]},a={cN:\"string\",b:/'/,e:/'/};return{aliases:[\"sh\",\"zsh\"],l:/\\b-?[a-z\\._]+\\b/,k:{keyword:\"if then else elif fi for while in do done case esac function\",literal:\"true false\",built_in:\"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp\",_:\"-ne -eq -lt -gt -f -d -e -s -l -a\"},c:[{cN:\"meta\",b:/^#![^\\n]+sh\\s*$/,r:10},{cN:\"function\",b:/\\w[\\w\\d_]*\\s*\\(\\s*\\)\\s*\\{/,rB:!0,c:[e.inherit(e.TM,{b:/\\w[\\w\\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage(\"java\",function(e){var a=\"[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*\",t=a+\"(<\"+a+\"(\\\\s*,\\\\s*\"+a+\")*>)?\",r=\"false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do\",s=\"\\\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\\\d]+[\\\\d_]+[\\\\d]+|[\\\\d]+)(\\\\.([\\\\d]+[\\\\d_]+[\\\\d]+|[\\\\d]+))?|\\\\.([\\\\d]+[\\\\d_]+[\\\\d]+|[\\\\d]+))([eE][-+]?\\\\d+)?)[lLfF]?\",c={cN:\"number\",b:s,r:0};return{aliases:[\"jsp\"],k:r,i:/<\\/|#/,c:[e.C(\"/\\\\*\\\\*\",\"\\\\*/\",{r:0,c:[{b:/\\w+@/,r:0},{cN:\"doctag\",b:\"@[A-Za-z]+\"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:\"class\",bK:\"class interface\",e:/[{;=]/,eE:!0,k:\"class interface\",i:/[:\"\\[\\]]/,c:[{bK:\"extends implements\"},e.UTM]},{bK:\"new throw return else\",r:0},{cN:\"function\",b:\"(\"+t+\"\\\\s+)+\"+e.UIR+\"\\\\s*\\\\(\",rB:!0,e:/[{;=]/,eE:!0,k:r,c:[{b:e.UIR+\"\\\\s*\\\\(\",rB:!0,r:0,c:[e.UTM]},{cN:\"params\",b:/\\(/,e:/\\)/,k:r,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},c,{cN:\"meta\",b:\"@[A-Za-z]+\"}]}});hljs.registerLanguage(\"perl\",function(e){var t=\"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when\",r={cN:\"subst\",b:\"[$@]\\\\{\",e:\"\\\\}\",k:t},s={b:\"->{\",e:\"}\"},n={v:[{b:/\\$\\d/},{b:/[\\$%@](\\^\\w\\b|#\\w+(::\\w+)*|{\\w+}|\\w+(::\\w*)*)/},{b:/[\\$%@][^\\s\\w{]/,r:0}]},i=[e.BE,r,n],o=[n,e.HCM,e.C(\"^\\\\=\\\\w\",\"\\\\=cut\",{eW:!0}),s,{cN:\"string\",c:i,v:[{b:\"q[qwxr]?\\\\s*\\\\(\",e:\"\\\\)\",r:5},{b:\"q[qwxr]?\\\\s*\\\\[\",e:\"\\\\]\",r:5},{b:\"q[qwxr]?\\\\s*\\\\{\",e:\"\\\\}\",r:5},{b:\"q[qwxr]?\\\\s*\\\\|\",e:\"\\\\|\",r:5},{b:\"q[qwxr]?\\\\s*\\\\<\",e:\"\\\\>\",r:5},{b:\"qw\\\\s+q\",e:\"q\",r:5},{b:\"'\",e:\"'\",c:[e.BE]},{b:'\"',e:'\"'},{b:\"`\",e:\"`\",c:[e.BE]},{b:\"{\\\\w+}\",c:[],r:0},{b:\"-?\\\\w+\\\\s*\\\\=\\\\>\",c:[],r:0}]},{cN:\"number\",b:\"(\\\\b0[0-7_]+)|(\\\\b0x[0-9a-fA-F_]+)|(\\\\b[1-9][0-9_]*(\\\\.[0-9_]+)?)|[0_]\\\\b\",r:0},{b:\"(\\\\/\\\\/|\"+e.RSR+\"|\\\\b(split|return|print|reverse|grep)\\\\b)\\\\s*\",k:\"split return print reverse grep\",r:0,c:[e.HCM,{cN:\"regexp\",b:\"(s|tr|y)/(\\\\\\\\.|[^/])*/(\\\\\\\\.|[^/])*/[a-z]*\",r:10},{cN:\"regexp\",b:\"(m|qr)?/\",e:\"/[a-z]*\",c:[e.BE],r:0}]},{cN:\"function\",bK:\"sub\",e:\"(\\\\s*\\\\(.*?\\\\))?[;{]\",eE:!0,r:5,c:[e.TM]},{b:\"-\\\\w\\\\b\",r:0},{b:\"^__DATA__$\",e:\"^__END__$\",sL:\"mojolicious\",c:[{b:\"^@@.*\",e:\"$\",cN:\"comment\"}]}];return r.c=o,s.c=o,{aliases:[\"pl\",\"pm\"],l:/[\\w\\.]+/,k:t,c:o}});hljs.registerLanguage(\"coffeescript\",function(e){var c={keyword:\"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super yield import export from as default await then unless until loop of by when and or is isnt not\",literal:\"true false null undefined yes no on off\",built_in:\"npm require console print module global window document\"},n=\"[A-Za-z$_][0-9A-Za-z$_]*\",r={cN:\"subst\",b:/#\\{/,e:/}/,k:c},i=[e.BNM,e.inherit(e.CNM,{starts:{e:\"(\\\\s*/)?\",r:0}}),{cN:\"string\",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/\"\"\"/,e:/\"\"\"/,c:[e.BE,r]},{b:/\"/,e:/\"/,c:[e.BE,r]}]},{cN:\"regexp\",v:[{b:\"///\",e:\"///\",c:[r,e.HCM]},{b:\"//[gim]*\",r:0},{b:/\\/(?![ *])(\\\\\\/|.)*?\\/[gim]*(?=\\W|$)/}]},{b:\"@\"+n},{sL:\"javascript\",eB:!0,eE:!0,v:[{b:\"```\",e:\"```\"},{b:\"`\",e:\"`\"}]}];r.c=i;var s=e.inherit(e.TM,{b:n}),t=\"(\\\\(.*\\\\))?\\\\s*\\\\B[-=]>\",o={cN:\"params\",b:\"\\\\([^\\\\(]\",rB:!0,c:[{b:/\\(/,e:/\\)/,k:c,c:[\"self\"].concat(i)}]};return{aliases:[\"coffee\",\"cson\",\"iced\"],k:c,i:/\\/\\*/,c:i.concat([e.C(\"###\",\"###\"),e.HCM,{cN:\"function\",b:\"^\\\\s*\"+n+\"\\\\s*=\\\\s*\"+t,e:\"[-=]>\",rB:!0,c:[s,o]},{b:/[:\\(,=]\\s*/,r:0,c:[{cN:\"function\",b:t,e:\"[-=]>\",rB:!0,c:[o]}]},{cN:\"class\",bK:\"class\",e:\"$\",i:/[:=\"\\[\\]]/,c:[{bK:\"extends\",eW:!0,i:/[:=\"\\[\\]]/,c:[s]},s]},{b:n+\":\",e:\":\",rB:!0,rE:!0,r:0}])}});hljs.registerLanguage(\"ruby\",function(e){var b=\"[a-zA-Z_]\\\\w*[!?=]?|[-+~]\\\\@|<<|>>|=~|===?|<=>|[<>]=?|\\\\*\\\\*|[-/+%^&*~`|]|\\\\[\\\\]=?\",r={keyword:\"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor\",literal:\"true false nil\"},c={cN:\"doctag\",b:\"@[A-Za-z]+\"},a={b:\"#<\",e:\">\"},s=[e.C(\"#\",\"$\",{c:[c]}),e.C(\"^\\\\=begin\",\"^\\\\=end\",{c:[c],r:10}),e.C(\"^__END__\",\"\\\\n$\")],n={cN:\"subst\",b:\"#\\\\{\",e:\"}\",k:r},t={cN:\"string\",c:[e.BE,n],v:[{b:/'/,e:/'/},{b:/\"/,e:/\"/},{b:/`/,e:/`/},{b:\"%[qQwWx]?\\\\(\",e:\"\\\\)\"},{b:\"%[qQwWx]?\\\\[\",e:\"\\\\]\"},{b:\"%[qQwWx]?{\",e:\"}\"},{b:\"%[qQwWx]?<\",e:\">\"},{b:\"%[qQwWx]?/\",e:\"/\"},{b:\"%[qQwWx]?%\",e:\"%\"},{b:\"%[qQwWx]?-\",e:\"-\"},{b:\"%[qQwWx]?\\\\|\",e:\"\\\\|\"},{b:/\\B\\?(\\\\\\d{1,3}|\\\\x[A-Fa-f0-9]{1,2}|\\\\u[A-Fa-f0-9]{4}|\\\\?\\S)\\b/},{b:/<<(-?)\\w+$/,e:/^\\s*\\w+$/}]},i={cN:\"params\",b:\"\\\\(\",e:\"\\\\)\",endsParent:!0,k:r},d=[t,a,{cN:\"class\",bK:\"class module\",e:\"$|;\",i:/=/,c:[e.inherit(e.TM,{b:\"[A-Za-z_]\\\\w*(::\\\\w+)*(\\\\?|\\\\!)?\"}),{b:\"<\\\\s*\",c:[{b:\"(\"+e.IR+\"::)?\"+e.IR}]}].concat(s)},{cN:\"function\",bK:\"def\",e:\"$|;\",c:[e.inherit(e.TM,{b:b}),i].concat(s)},{b:e.IR+\"::\"},{cN:\"symbol\",b:e.UIR+\"(\\\\!|\\\\?)?:\",r:0},{cN:\"symbol\",b:\":(?!\\\\s)\",c:[t,{b:b}],r:0},{cN:\"number\",b:\"(\\\\b0[0-7_]+)|(\\\\b0x[0-9a-fA-F_]+)|(\\\\b[1-9][0-9_]*(\\\\.[0-9_]+)?)|[0_]\\\\b\",r:0},{b:\"(\\\\$\\\\W)|((\\\\$|\\\\@\\\\@?)(\\\\w+))\"},{cN:\"params\",b:/\\|/,e:/\\|/,k:r},{b:\"(\"+e.RSR+\"|unless)\\\\s*\",k:\"unless\",c:[a,{cN:\"regexp\",c:[e.BE,n],i:/\\n/,v:[{b:\"/\",e:\"/[a-z]*\"},{b:\"%r{\",e:\"}[a-z]*\"},{b:\"%r\\\\(\",e:\"\\\\)[a-z]*\"},{b:\"%r!\",e:\"![a-z]*\"},{b:\"%r\\\\[\",e:\"\\\\][a-z]*\"}]}].concat(s),r:0}].concat(s);n.c=d,i.c=d;var l=\"[>?]>\",o=\"[\\\\w#]+\\\\(\\\\w+\\\\):\\\\d+:\\\\d+>\",u=\"(\\\\w+-)?\\\\d+\\\\.\\\\d+\\\\.\\\\d(p\\\\d+)?[^>]+>\",w=[{b:/^\\s*=>/,starts:{e:\"$\",c:d}},{cN:\"meta\",b:\"^(\"+l+\"|\"+o+\"|\"+u+\")\",starts:{e:\"$\",c:d}}];return{aliases:[\"rb\",\"gemspec\",\"podspec\",\"thor\",\"irb\"],k:r,i:/\\/\\*/,c:s.concat(w).concat(d)}});hljs.registerLanguage(\"css\",function(e){var c=\"[a-zA-Z-][a-zA-Z0-9_-]*\",t={b:/[A-Z\\_\\.\\-]+\\s*:/,rB:!0,e:\";\",eW:!0,c:[{cN:\"attribute\",b:/\\S/,e:\":\",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\\w-]+\\(/,rB:!0,c:[{cN:\"built_in\",b:/[\\w-]+/},{b:/\\(/,e:/\\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:\"number\",b:\"#[0-9A-Fa-f]+\"},{cN:\"meta\",b:\"!important\"}]}}]};return{cI:!0,i:/[=\\/|'\\$]/,c:[e.CBCM,{cN:\"selector-id\",b:/#[A-Za-z0-9_-]+/},{cN:\"selector-class\",b:/\\.[A-Za-z0-9_-]+/},{cN:\"selector-attr\",b:/\\[/,e:/\\]/,i:\"$\"},{cN:\"selector-pseudo\",b:/:(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\"'.]+/},{b:\"@(font-face|page)\",l:\"[a-z-]+\",k:\"font-face page\"},{b:\"@\",e:\"[{;]\",i:/:/,c:[{cN:\"keyword\",b:/\\w+/},{b:/\\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:\"selector-tag\",b:c,r:0},{b:\"{\",e:\"}\",i:/\\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage(\"cpp\",function(t){var e={cN:\"keyword\",b:\"\\\\b[a-z\\\\d_]*_t\\\\b\"},r={cN:\"string\",v:[{b:'(u8?|U)?L?\"',e:'\"',i:\"\\\\n\",c:[t.BE]},{b:'(u8?|U)?R\"',e:'\"',c:[t.BE]},{b:\"'\\\\\\\\?.\",e:\"'\",i:\".\"}]},s={cN:\"number\",v:[{b:\"\\\\b(0b[01']+)\"},{b:\"(-?)\\\\b([\\\\d']+(\\\\.[\\\\d']*)?|\\\\.[\\\\d']+)(u|U|l|L|ul|UL|f|F|b|B)\"},{b:\"(-?)(\\\\b0[xX][a-fA-F0-9']+|(\\\\b[\\\\d']+(\\\\.[\\\\d']*)?|\\\\.[\\\\d']+)([eE][-+]?[\\\\d']+)?)\"}],r:0},i={cN:\"meta\",b:/#\\s*[a-z]+\\b/,e:/$/,k:{\"meta-keyword\":\"if else elif endif define undef warning error line pragma ifdef ifndef include\"},c:[{b:/\\\\\\n/,r:0},t.inherit(r,{cN:\"meta-string\"}),{cN:\"meta-string\",b:/<[^\\n>]*>/,e:/$/,i:\"\\\\n\"},t.CLCM,t.CBCM]},a=t.IR+\"\\\\s*\\\\(\",c={keyword:\"int float while private char catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignof constexpr decltype noexcept static_assert thread_local restrict _Bool complex _Complex _Imaginary atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and or not\",built_in:\"std string cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr\",literal:\"true false nullptr NULL\"},n=[e,t.CLCM,t.CBCM,s,r];return{aliases:[\"c\",\"cc\",\"h\",\"c++\",\"h++\",\"hpp\"],k:c,i:\"</\",c:n.concat([i,{b:\"\\\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\\\s*<\",e:\">\",k:c,c:[\"self\",e]},{b:t.IR+\"::\",k:c},{v:[{b:/=/,e:/;/},{b:/\\(/,e:/\\)/},{bK:\"new throw return else\",e:/;/}],k:c,c:n.concat([{b:/\\(/,e:/\\)/,k:c,c:n.concat([\"self\"]),r:0}]),r:0},{cN:\"function\",b:\"(\"+t.IR+\"[\\\\*&\\\\s]+)+\"+a,rB:!0,e:/[{;=]/,eE:!0,k:c,i:/[^\\w\\s\\*&]/,c:[{b:a,rB:!0,c:[t.TM],r:0},{cN:\"params\",b:/\\(/,e:/\\)/,k:c,r:0,c:[t.CLCM,t.CBCM,r,s,e]},t.CLCM,t.CBCM,i]},{cN:\"class\",bK:\"class struct\",e:/[{;:]/,c:[{b:/</,e:/>/,c:[\"self\"]},t.TM]}]),exports:{preprocessor:i,strings:r,k:c}}});hljs.registerLanguage(\"shell\",function(s){return{aliases:[\"console\"],c:[{cN:\"meta\",b:\"^\\\\s{0,3}[\\\\w\\\\d\\\\[\\\\]()@-]*[>%$#]\",starts:{e:\"$\",sL:\"bash\"}}]}});hljs.registerLanguage(\"objectivec\",function(e){var t={cN:\"built_in\",b:\"\\\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\\\w+\"},_={keyword:\"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN\",literal:\"false true FALSE TRUE nil YES NO NULL\",built_in:\"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once\"},i=/[a-zA-Z@][a-zA-Z0-9_]*/,n=\"@interface @class @protocol @implementation\";return{aliases:[\"mm\",\"objc\",\"obj-c\"],k:_,l:i,i:\"</\",c:[t,e.CLCM,e.CBCM,e.CNM,e.QSM,{cN:\"string\",v:[{b:'@\"',e:'\"',i:\"\\\\n\",c:[e.BE]},{b:\"'\",e:\"[^\\\\\\\\]'\",i:\"[^\\\\\\\\][^']\"}]},{cN:\"meta\",b:\"#\",e:\"$\",c:[{cN:\"meta-string\",v:[{b:'\"',e:'\"'},{b:\"<\",e:\">\"}]}]},{cN:\"class\",b:\"(\"+n.split(\" \").join(\"|\")+\")\\\\b\",e:\"({|$)\",eE:!0,k:n,l:i,c:[e.UTM]},{b:\"\\\\.\"+e.UIR,r:0}]}});hljs.registerLanguage(\"ini\",function(e){var b={cN:\"string\",c:[e.BE],v:[{b:\"'''\",e:\"'''\",r:10},{b:'\"\"\"',e:'\"\"\"',r:10},{b:'\"',e:'\"'},{b:\"'\",e:\"'\"}]};return{aliases:[\"toml\"],cI:!0,i:/\\S/,c:[e.C(\";\",\"$\"),e.HCM,{cN:\"section\",b:/^\\s*\\[+/,e:/\\]+/},{b:/^[a-z0-9\\[\\]_-]+\\s*=\\s*/,e:\"$\",rB:!0,c:[{cN:\"attr\",b:/[a-z0-9\\[\\]_-]+/},{b:/=/,eW:!0,r:0,c:[{cN:\"literal\",b:/\\bon|off|true|false|yes|no\\b/},{cN:\"variable\",v:[{b:/\\$[\\w\\d\"][\\w\\d_]*/},{b:/\\$\\{(.*?)}/}]},b,{cN:\"number\",b:/([\\+\\-]+)?[\\d]+_[\\d_]+/},e.NM]}]}]}});hljs.registerLanguage(\"makefile\",function(e){var i={cN:\"variable\",v:[{b:\"\\\\$\\\\(\"+e.UIR+\"\\\\)\",c:[e.BE]},{b:/\\$[@%<?\\^\\+\\*]/}]},r={cN:\"string\",b:/\"/,e:/\"/,c:[e.BE,i]},a={cN:\"variable\",b:/\\$\\([\\w-]+\\s/,e:/\\)/,k:{built_in:\"subst patsubst strip findstring filter filter-out sort word wordlist firstword lastword dir notdir suffix basename addsuffix addprefix join wildcard realpath abspath error warning shell origin flavor foreach if or and call eval file value\"},c:[i]},n={b:\"^\"+e.UIR+\"\\\\s*[:+?]?=\",i:\"\\\\n\",rB:!0,c:[{b:\"^\"+e.UIR,e:\"[:+?]?=\",eE:!0}]},t={cN:\"meta\",b:/^\\.PHONY:/,e:/$/,k:{\"meta-keyword\":\".PHONY\"},l:/[\\.\\w]+/},l={cN:\"section\",b:/^[^\\s]+:/,e:/$/,c:[i]};return{aliases:[\"mk\",\"mak\"],k:\"define endef undefine ifdef ifndef ifeq ifneq else endif include -include sinclude override export unexport private vpath\",l:/[\\w-]+/,c:[e.HCM,i,r,a,n,t,l]}});hljs.registerLanguage(\"python\",function(e){var r={keyword:\"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda async await nonlocal|10 None True False\",built_in:\"Ellipsis NotImplemented\"},b={cN:\"meta\",b:/^(>>>|\\.\\.\\.) /},c={cN:\"subst\",b:/\\{/,e:/\\}/,k:r,i:/#/},a={cN:\"string\",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[b],r:10},{b:/(u|b)?r?\"\"\"/,e:/\"\"\"/,c:[b],r:10},{b:/(fr|rf|f)'''/,e:/'''/,c:[b,c]},{b:/(fr|rf|f)\"\"\"/,e:/\"\"\"/,c:[b,c]},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)\"/,e:/\"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)\"/,e:/\"/},{b:/(fr|rf|f)'/,e:/'/,c:[c]},{b:/(fr|rf|f)\"/,e:/\"/,c:[c]},e.ASM,e.QSM]},s={cN:\"number\",r:0,v:[{b:e.BNR+\"[lLjJ]?\"},{b:\"\\\\b(0o[0-7]+)[lLjJ]?\"},{b:e.CNR+\"[lLjJ]?\"}]},i={cN:\"params\",b:/\\(/,e:/\\)/,c:[\"self\",b,s,a]};return c.c=[a,s,b],{aliases:[\"py\",\"gyp\"],k:r,i:/(<\\/|->|\\?)|=>/,c:[b,s,a,e.HCM,{v:[{cN:\"function\",bK:\"def\"},{cN:\"class\",bK:\"class\"}],e:/:/,i:/[${=;\\n,]/,c:[e.UTM,i,{b:/->/,eW:!0,k:\"None\"}]},{cN:\"meta\",b:/^[\\t ]*@/,e:/$/},{b:/\\b(print|exec)\\(/}]}});hljs.registerLanguage(\"json\",function(e){var i={literal:\"true false null\"},n=[e.QSM,e.CNM],r={e:\",\",eW:!0,eE:!0,c:n,k:i},t={b:\"{\",e:\"}\",c:[{cN:\"attr\",b:/\"/,e:/\"/,c:[e.BE],i:\"\\\\n\"},e.inherit(r,{b:/:/})],i:\"\\\\S\"},c={b:\"\\\\[\",e:\"\\\\]\",c:[e.inherit(r)],i:\"\\\\S\"};return n.splice(n.length,0,t,c),{c:n,k:i,i:\"\\\\S\"}});hljs.registerLanguage(\"apache\",function(e){var r={cN:\"number\",b:\"[\\\\$%]\\\\d+\"};return{aliases:[\"apacheconf\"],cI:!0,c:[e.HCM,{cN:\"section\",b:\"</?\",e:\">\"},{cN:\"attribute\",b:/\\w+/,r:0,k:{nomarkup:\"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername\"},starts:{e:/$/,r:0,k:{literal:\"on off all\"},c:[{cN:\"meta\",b:\"\\\\s\\\\[\",e:\"\\\\]$\"},{cN:\"variable\",b:\"[\\\\$%]\\\\{\",e:\"\\\\}\",c:[\"self\",r]},r,e.QSM]}}],i:/\\S/}});hljs.registerLanguage(\"cs\",function(e){var i={keyword:\"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long nameof object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let on orderby partial remove select set value var where yield\",literal:\"null false true\"},t={cN:\"string\",b:'@\"',e:'\"',c:[{b:'\"\"'}]},r=e.inherit(t,{i:/\\n/}),a={cN:\"subst\",b:\"{\",e:\"}\",k:i},c=e.inherit(a,{i:/\\n/}),n={cN:\"string\",b:/\\$\"/,e:'\"',i:/\\n/,c:[{b:\"{{\"},{b:\"}}\"},e.BE,c]},s={cN:\"string\",b:/\\$@\"/,e:'\"',c:[{b:\"{{\"},{b:\"}}\"},{b:'\"\"'},a]},o=e.inherit(s,{i:/\\n/,c:[{b:\"{{\"},{b:\"}}\"},{b:'\"\"'},c]});a.c=[s,n,t,e.ASM,e.QSM,e.CNM,e.CBCM],c.c=[o,n,r,e.ASM,e.QSM,e.CNM,e.inherit(e.CBCM,{i:/\\n/})];var l={v:[s,n,t,e.ASM,e.QSM]},b=e.IR+\"(<\"+e.IR+\"(\\\\s*,\\\\s*\"+e.IR+\")*>)?(\\\\[\\\\])?\";return{aliases:[\"csharp\"],k:i,i:/::/,c:[e.C(\"///\",\"$\",{rB:!0,c:[{cN:\"doctag\",v:[{b:\"///\",r:0},{b:\"<!--|-->\"},{b:\"</?\",e:\">\"}]}]}),e.CLCM,e.CBCM,{cN:\"meta\",b:\"#\",e:\"$\",k:{\"meta-keyword\":\"if else elif endif define undef warning error line region endregion pragma checksum\"}},l,e.CNM,{bK:\"class interface\",e:/[{;=]/,i:/[^\\s:]/,c:[e.TM,e.CLCM,e.CBCM]},{bK:\"namespace\",e:/[{;=]/,i:/[^\\s:]/,c:[e.inherit(e.TM,{b:\"[a-zA-Z](\\\\.?\\\\w)*\"}),e.CLCM,e.CBCM]},{cN:\"meta\",b:\"^\\\\s*\\\\[\",eB:!0,e:\"\\\\]\",eE:!0,c:[{cN:\"meta-string\",b:/\"/,e:/\"/}]},{bK:\"new return throw await else\",r:0},{cN:\"function\",b:\"(\"+b+\"\\\\s+)+\"+e.IR+\"\\\\s*\\\\(\",rB:!0,e:/[{;=]/,eE:!0,k:i,c:[{b:e.IR+\"\\\\s*\\\\(\",rB:!0,c:[e.TM],r:0},{cN:\"params\",b:/\\(/,e:/\\)/,eB:!0,eE:!0,k:i,r:0,c:[l,e.CNM,e.CBCM]},e.CLCM,e.CBCM]}]}});hljs.registerLanguage(\"sql\",function(e){var t=e.C(\"--\",\"$\");return{cI:!0,i:/[<>{}*#]/,c:[{bK:\"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment\",e:/;/,eW:!0,l:/[\\w\\.]+/,k:{keyword:\"abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek\",literal:\"true false null\",built_in:\"array bigint binary bit blob boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text varchar varying void\"},c:[{cN:\"string\",b:\"'\",e:\"'\",c:[e.BE,{b:\"''\"}]},{cN:\"string\",b:'\"',e:'\"',c:[e.BE,{b:'\"\"'}]},{cN:\"string\",b:\"`\",e:\"`\",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}});hljs.registerLanguage(\"php\",function(e){var c={b:\"\\\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*\"},i={cN:\"meta\",b:/<\\?(php)?|\\?>/},t={cN:\"string\",c:[e.BE,i],v:[{b:'b\"',e:'\"'},{b:\"b'\",e:\"'\"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},a={v:[e.BNM,e.CNM]};return{aliases:[\"php3\",\"php4\",\"php5\",\"php6\"],cI:!0,k:\"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally\",c:[e.HCM,e.C(\"//\",\"$\",{c:[i]}),e.C(\"/\\\\*\",\"\\\\*/\",{c:[{cN:\"doctag\",b:\"@[A-Za-z]+\"}]}),e.C(\"__halt_compiler.+?;\",!1,{eW:!0,k:\"__halt_compiler\",l:e.UIR}),{cN:\"string\",b:/<<<['\"]?\\w+['\"]?$/,e:/^\\w+;?$/,c:[e.BE,{cN:\"subst\",v:[{b:/\\$\\w+/},{b:/\\{\\$/,e:/\\}/}]}]},i,{cN:\"keyword\",b:/\\$this\\b/},c,{b:/(::|->)+[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*/},{cN:\"function\",bK:\"function\",e:/[;{]/,eE:!0,i:\"\\\\$|\\\\[|%\",c:[e.UTM,{cN:\"params\",b:\"\\\\(\",e:\"\\\\)\",c:[\"self\",c,e.CBCM,t,a]}]},{cN:\"class\",bK:\"class interface\",e:\"{\",eE:!0,i:/[:\\(\\$\"]/,c:[{bK:\"extends implements\"},e.UTM]},{bK:\"namespace\",e:\";\",i:/[\\.']/,c:[e.UTM]},{bK:\"use\",e:\";\",c:[e.UTM]},{b:\"=>\"},t,a]}});hljs.registerLanguage(\"http\",function(e){var t=\"HTTP/[0-9\\\\.]+\";return{aliases:[\"https\"],i:\"\\\\S\",c:[{b:\"^\"+t,e:\"$\",c:[{cN:\"number\",b:\"\\\\b\\\\d{3}\\\\b\"}]},{b:\"^[A-Z]+ (.*?) \"+t+\"$\",rB:!0,e:\"$\",c:[{cN:\"string\",b:\" \",e:\" \",eB:!0,eE:!0},{b:t},{cN:\"keyword\",b:\"[A-Z]+\"}]},{cN:\"attribute\",b:\"^\\\\w\",e:\": \",eE:!0,i:\"\\\\n|\\\\s|=\",starts:{e:\"$\",r:0}},{b:\"\\\\n\\\\n\",starts:{sL:[],eW:!0}}]}});"
  },
  {
    "path": "platform/public/lib/webpack/.gitkeep",
    "content": ""
  },
  {
    "path": "platform/public/other/.gitkeep",
    "content": ""
  },
  {
    "path": "platform/resources/challenges/templates/template.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nint main(int argc, char **argv) {\n    %%_INSERTVALUES_%%\n\n    // write your solution here\n}\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.cpp",
    "content": "#include <iostream>\n#include <string>\n\nint main(int argc, char **argv) {\n    %%_INSERTVALUES_%%\n\n    // write your solution here\n}\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.cs",
    "content": "using System;\n\nclass MainClass {\n    static void Main(string[] args) {\n        %%_INSERTVALUES_%%\n\n        // write your solution here\n    }\n}\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.go",
    "content": "package main\n\nimport (\n    \"os\"\n    \"fmt\"\n    %%_IMPORTS_%%\n)\n\nfunc main() {\n    %%_INSERTVALUES_%%\n\n    // write your solution here\n}\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.hs",
    "content": "import System.Environment\n\nmain = do\n    args <- getArgs\n    %%_INSERTVALUES_%%\n    -- write your solution here\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.java",
    "content": "public class Main {\n    public static void main(String[] args) {\n        %%_INSERTVALUES_%%\n\n        // write your solution here\n    }\n}\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.jl",
    "content": "%%_INSERTVALUES_%%\n\n# write your solution here\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.js",
    "content": "%%_INSERTVALUES_%%\n\n// write your solution here\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.kt",
    "content": "fun main(args: Array<String>) {\n    %%_INSERTVALUES_%%\n\n    // write your solution here\n}\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.nim",
    "content": "%%_INSERTVALUES_%%\n\n# write your solution here\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.php",
    "content": "<?php\n\n%%_INSERTVALUES_%%\n\n// write your solution here\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.pl",
    "content": "%%_INSERTVALUES_%%\n\n# write your solution here\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.py",
    "content": "import sys\n\n%%_INSERTVALUES_%%\n\n# write your solution here\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.rb",
    "content": "%%_INSERTVALUES_%%\n\n# write your solution here\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.rs",
    "content": "#![allow(dead_code,unused_variables)]\n\nuse std::env;\n\nfn main() {\n    let args: Vec<String> = env::args().collect();\n\n    %%_INSERTVALUES_%%\n\n    // write your solution here\n}\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.sh",
    "content": "%%_INSERTVALUES_%%\n\n# write your solution here\n"
  },
  {
    "path": "platform/resources/challenges/templates/template.swift",
    "content": "%%_INSERTVALUES_%%\n\n// write your solution here\n"
  },
  {
    "path": "platform/resources/js/.gitkeep",
    "content": ""
  },
  {
    "path": "platform/resources/js/challenges/get_language_version.js",
    "content": "import axios from 'axios';\n\n$(document).ready(async function () {\n    if ($('.get-versions').length > 0) {\n        var languages = await axios.get('/api/v1/piston/versions');\n        $('.version').each(function () {\n            let language = languages.data.filter(\n                (lang) => $(this).data('langname') === lang.name\n            )[0];\n            $(this).append(language.version);\n        });\n    }\n});\n"
  },
  {
    "path": "platform/resources/js/common.js",
    "content": "const Constants = {\n    exp_mo: [\n        '01',\n        '02',\n        '03',\n        '04',\n        '05',\n        '06',\n        '07',\n        '08',\n        '09',\n        '10',\n        '11',\n        '12'\n    ],\n\n    exp_yr: new Array(10).fill(new Date().getFullYear()).map((n, i) => n + i)\n};\n\nexport default Constants;\n"
  },
  {
    "path": "platform/resources/js/snippets/delete_snippet.js",
    "content": "import axios from 'axios';\n\n$(document).on('click', '.confirm-delete', function (e) {\n    var hash = $(this).data('hash');\n\n    bootbox.confirm({\n        message: 'Are you sure you want to delete this snippet?',\n        buttons: {\n            confirm: {\n                label: 'Delete',\n                className: 'btn-danger'\n            },\n            cancel: {\n                label: 'Cancel',\n                className: 'btn-secondary'\n            }\n        },\n        callback: async function (result) {\n            if (result) {\n                let res = await axios.post('/snippets/delete/' + hash);\n                location = res.data.url;\n            }\n        }\n    });\n});\n"
  },
  {
    "path": "platform/resources/js/util.js",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\n\nclass Util {\n    static unpack_props(props) {\n        for (const key in props) {\n            try {\n                props[key] = JSON.parse(props[key]);\n            } catch (e) {}\n        }\n    }\n\n    static try_render(id, comp) {\n        if (document.getElementById(id)) {\n            let ele = document.getElementById(id);\n\n            const final = {};\n\n            for (const key in ele.dataset) {\n                try {\n                    final[key] = JSON.parse(ele.dataset[key]);\n                } catch (e) {}\n            }\n\n            return ReactDOM.render(\n                React.createElement(comp, final),\n                document.getElementById(id)\n            );\n        }\n    }\n\n    static are_test_cases_valid(test_object) {\n        return (\n            test_object.input !== '' &&\n            test_object.output !== '' &&\n            test_object.input.split('\\n').length ===\n                test_object.output.split('\\n').length\n        );\n    }\n}\n\nexport default Util;\n"
  },
  {
    "path": "platform/resources/jsx/challenges/challenge.jsx",
    "content": "import React from 'react';\nimport axios from 'axios';\n\nimport Util from 'js/util';\n\nclass Challenge extends React.Component {\n    constructor(props) {\n        super(props);\n\n        this.state = {\n            solved: props.solved,\n            challenge: props.challenge,\n            language: props.language,\n            template:\n                (props.challenge.solution &&\n                    props.challenge.solution.solution) ||\n                props.template,\n            abstract: props.abstract,\n            monaco_language: props.monaco_language,\n            executing: false,\n            test_results: [],\n            changed: false\n        };\n\n        this.execute = this.execute.bind(this);\n        this.editor_change = this.editor_change.bind(this);\n        this.before_unload = this.before_unload.bind(this);\n\n        // Add event listener for when the user leaves with unsaved work\n        window.addEventListener('beforeunload', this.before_unload, false);\n    }\n\n    componentDidMount() {\n        this.editor = monaco.editor.create(document.getElementById('editor'), {\n            theme: 'em',\n            language: this.state.monaco_language,\n            value: this.state.template,\n            automaticLayout: true,\n            fontSize: 16\n        });\n\n        // Bind event listener for when the editor changes; unsaved work\n        this.editor.onDidChangeModelContent(this.editor_change);\n    }\n\n    componentWillUnmount() {\n        // Remove event listener on unmount\n        window.removeEventListener('beforeunload', this.before_unload, false);\n    }\n\n    async execute() {\n        this.setState({\n            executing: true,\n            test_results: []\n        });\n\n        let res = await axios.post(\n            '/challenges/execute/' + this.state.challenge.challenge_id,\n            {\n                language: this.state.language,\n                source: this.editor.getValue()\n            }\n        );\n\n        if (res.status >= 400) {\n            return bootbox.alert(\n                'An error has occured, please try again later.'\n            );\n        }\n\n        let solved = res.data.filter((r) => !r.passed).length === 0;\n\n        if (solved) {\n            this.setState((prev) => {\n                if (!prev.solved) {\n                    let alert_message = !!prev.challenge.draft\n                        ? 'Thank you for testing EMKC challenges!<br />\\\n                        Your answer will not be saved since this challenge is still under construction.'\n                        : 'Congratulations, you solved this challenge!';\n\n                    bootbox.alert(alert_message);\n                }\n\n                return {\n                    solved: true,\n\n                    // The challenge's code saves on solve\n                    // Therefore, we can disable the \"close protection\"\n                    changed: false\n                };\n            });\n        }\n\n        return this.setState({\n            executing: false,\n            test_results: res.data\n        });\n    }\n\n    editor_change(_) {\n        // Only change state when necessary\n        if (!this.state.changed) {\n            // The editor's contents have changed\n            this.setState({\n                changed: true\n            });\n        }\n    }\n\n    before_unload(e) {\n        if (this.state.changed) {\n            // Unsaved work, prompt user!\n            e.preventDefault();\n            e.returnValue = true;\n        }\n    }\n\n    render() {\n        let text_color;\n\n        switch (this.state.challenge.difficulty) {\n            case 1:\n                text_color = 'easy';\n                break;\n            case 2:\n                text_color = 'medium';\n                break;\n            case 3:\n                text_color = 'hard';\n                break;\n        }\n\n        return (\n            <div class=\"em_challenge\">\n                <div class=\"instructions\">\n                    <h3 class={text_color}>{this.state.challenge.name}</h3>\n                    <p>{this.state.challenge.description}</p>\n                    <span\n                        class={\n                            'badge badge-' +\n                            (this.state.solved ? text_color : 'light')\n                        }\n                    >\n                        {this.state.solved ? 'Solved' : 'Unsolved'}\n                    </span>\n                    <hr />\n                    <button\n                        class=\"btn btn-primary btn-block\"\n                        onClick={this.execute}\n                        disabled={this.state.executing}\n                    >\n                        Execute\n                    </button>\n                    <hr />\n                    <div\n                        class=\"abstract\"\n                        dangerouslySetInnerHTML={{\n                            __html: this.state.abstract\n                        }}\n                    ></div>\n                </div>\n                <div class=\"editor\">\n                    <div id=\"editor\"></div>\n                </div>\n                <div class=\"results\">\n                    <h4 class=\"f300\">Test Results</h4>\n                    {this.state.test_results.map((result) => {\n                        return (\n                            <div key={result.name} class=\"result\">\n                                <span class=\"f700\">{result.name}</span>{' '}\n                                <span\n                                    class={\n                                        'badge badge-' +\n                                        (result.passed ? 'success' : 'danger')\n                                    }\n                                >\n                                    {result.passed ? 'passed' : 'failed'}\n                                </span>\n                                <br />\n                                {result.input.map((input, i) => {\n                                    return (\n                                        <React.Fragment key={i}>\n                                            <span class=\"badge badge-info\">\n                                                value{i + 1}\n                                            </span>{' '}\n                                            {input}\n                                            <br />\n                                        </React.Fragment>\n                                    );\n                                })}\n                                <span class=\"badge badge-dark\">\n                                    expected output\n                                </span>{' '}\n                                {result.expected}\n                                <br />\n                                <span class=\"badge badge-dark\">\n                                    actual output\n                                </span>{' '}\n                                <pre>{result.actual}</pre>\n                                {!!result.compile_output && (\n                                    <>\n                                        <br />\n                                        <span class=\"badge badge-dark\">\n                                            compile output\n                                        </span>{' '}\n                                        <br />\n                                        <pre>{result.compile_output}</pre>\n                                    </>\n                                )}\n                                {!!result.run_error && (\n                                    <>\n                                        <br />\n                                        <span class=\"badge badge-dark\">\n                                            run error\n                                        </span>{' '}\n                                        <br />\n                                        <pre>{result.run_error}</pre>\n                                    </>\n                                )}\n                            </div>\n                        );\n                    })}\n                </div>\n            </div>\n        );\n    }\n}\n\nUtil.try_render('react_challenge', Challenge);\n\nexport default Challenge;\n"
  },
  {
    "path": "platform/resources/jsx/challenges/manage_challenge.jsx",
    "content": "import React from 'react';\nimport axios from 'axios';\nimport Quill from 'quill';\n\nimport Util from 'js/util';\n\nclass ManageChallenge extends React.Component {\n    constructor(props) {\n        super(props);\n\n        this.state = {\n            ...props.challenge,\n            challenge_id:\n                this.props.mode === 'create'\n                    ? -1\n                    : this.props.challenge.challenge_id,\n            editing_test: {} // The test being edited (to show edit section)\n        };\n\n        this.handle_change = this.handle_change.bind(this);\n        this.manage_test = this.manage_test.bind(this);\n        this.save_test = this.save_test.bind(this);\n        this.delete_test = this.delete_test.bind(this);\n        this.save = this.save.bind(this);\n    }\n\n    componentDidMount() {\n        let Inline = Quill.import('blots/inline');\n\n        class Badge extends Inline {}\n        Badge.blotName = 'badge';\n        Badge.tagName = 'span';\n        Badge.className = 'value-badge';\n        Badge.formats = () => true;\n\n        Quill.register(Badge);\n\n        let quill = new Quill('#html', {\n            theme: 'snow',\n            modules: {\n                syntax: false,\n                toolbar: [\n                    ['bold', 'italic', 'underline', 'strike'],\n                    [\n                        { header: 1 },\n                        { header: 2 },\n                        { header: 3 },\n                        { header: 4 }\n                    ],\n                    ['blockquote', 'code-block', 'link'],\n                    [{ list: 'ordered' }, { list: 'bullet' }],\n                    //['badge'],\n                    ['clean']\n                ]\n            }\n        });\n\n        quill.on('text-change', () => {\n            this.setState({\n                html: quill.root.innerHTML\n            });\n        });\n\n        if (this.props.mode === 'update') {\n            quill.clipboard.dangerouslyPasteHTML(this.state.html);\n        }\n    }\n\n    handle_change(e) {\n        let id = e.target.id;\n        let value = e.target.value;\n\n        // Handles changes in challenge data\n        if (id.indexOf('test-') === -1) {\n            if (id === 'draft') {\n                value = this.state.draft ? 0 : 1;\n            }\n\n            return this.setState({\n                [id]: value\n            });\n        }\n\n        // Handles changes in tests data\n        const editing_test = this.state.editing_test;\n        editing_test[id.replace('test-', '')] = value;\n\n        return this.setState({ editing_test });\n    }\n\n    async save() {\n        if (this.state.tests.length === 0) {\n            return bootbox.alert('Please add at least one test.');\n        }\n\n        let url =\n            this.props.mode === 'create'\n                ? '/admin/challenges/create'\n                : '/admin/challenges/update/' + this.state.challenge_id;\n\n        let res = await axios.post(url, {\n            draft: this.state.draft,\n            difficulty: this.state.difficulty,\n            points: this.state.points,\n            name: this.state.name,\n            description: this.state.description,\n            html: this.state.html,\n            tests: this.state.tests\n        });\n\n        if (res.status >= 400) {\n            return bootbox.alert('An error has occurred');\n        }\n\n        location = '/admin/challenges';\n    }\n\n    manage_test(editing_test) {\n        this.setState({ editing_test });\n    }\n\n    async delete_test(index_to_delete) {\n        let current_tests = this.state.tests;\n        current_tests.splice(index_to_delete, 1);\n        this.setState({ tests: current_tests, editing_test: {} });\n    }\n\n    async save_test() {\n        let current_tests = this.state.tests;\n        let editing_test = this.state.editing_test;\n\n        if (!editing_test.name || !editing_test.input || !editing_test.output) {\n            return bootbox.alert('Please provide all data.');\n        }\n\n        if (!Util.are_test_cases_valid(editing_test)) {\n            return bootbox.alert('Invalid test cases');\n        }\n\n        if (editing_test.index === -1) {\n            current_tests.push(editing_test);\n\n            return this.setState({\n                tests: current_tests,\n                editing_test: {}\n            });\n        }\n\n        let test_to_edit = current_tests[editing_test.index];\n\n        current_tests.splice(\n            current_tests.indexOf(test_to_edit),\n            1,\n            editing_test\n        );\n\n        return this.setState({\n            tests: current_tests,\n            editing_test: {}\n        });\n    }\n\n    render() {\n        return (\n            <div class=\"em_challenge_manage marginbottom20\">\n                <h4 class=\"f300\">Manage Challenge</h4>\n\n                {this.state.html.indexOf('em_challenge_abstract\"') !== -1 && (\n                    <div class=\"alert alert-danger\">\n                        Editing is not supported for this challenge unless\n                        reformatted.\n                    </div>\n                )}\n                <div class=\"form-group\">\n                    <label>\n                        Name\n                        <input\n                            type=\"text\"\n                            id=\"name\"\n                            class=\"form-control\"\n                            value={this.state.name}\n                            onChange={this.handle_change}\n                        />\n                    </label>\n                </div>\n\n                <div class=\"form-group\">\n                    <div class=\"checkbox\">\n                        <input\n                            type=\"checkbox\"\n                            id=\"draft\"\n                            checked={this.state.draft}\n                            onChange={this.handle_change}\n                        />{' '}\n                        Draft\n                    </div>\n                </div>\n\n                <div class=\"form-group\">\n                    <label>\n                        Difficulty\n                        <select\n                            type=\"text\"\n                            id=\"difficulty\"\n                            class=\"form-control\"\n                            value={this.state.difficulty}\n                            onChange={this.handle_change}\n                        >\n                            <option value=\"1\">Easy</option>\n                            <option value=\"2\">Medium</option>\n                            <option value=\"3\">Hard</option>\n                        </select>\n                    </label>\n                </div>\n\n                <div class=\"form-group\">\n                    <label>\n                        Points (the standard is: easy: 10, medium: 30, hard: 50)\n                        <input\n                            type=\"text\"\n                            id=\"points\"\n                            class=\"form-control\"\n                            value={this.state.points}\n                            onChange={this.handle_change}\n                        />\n                    </label>\n                </div>\n\n                <div class=\"form-group\">\n                    <label>Brief description</label>\n\n                    <input\n                        type=\"text\"\n                        id=\"description\"\n                        class=\"form-control\"\n                        value={this.state.description}\n                        onChange={this.handle_change}\n                    />\n                </div>\n\n                <div class=\"form-group\">\n                    <label>Challenge explanation</label>\n                    <div id=\"html\"></div>\n                </div>\n                <div class=\"form-group\">\n                    <h4 class=\"f300\">\n                        Test Cases\n                        <small>\n                            <a\n                                class=\"pointer\"\n                                onClick={() =>\n                                    this.manage_test({\n                                        challenge_id: this.state.challenge_id,\n                                        name: '',\n                                        input: '',\n                                        output: '',\n                                        index: -1\n                                    })\n                                }\n                            >\n                                {' '}\n                                <i class=\"fa fa-plus green\"></i>\n                            </a>\n                        </small>\n                    </h4>\n                    {Object.keys(this.state.editing_test).length > 0 && (\n                        <div class=\"case_box\">\n                            <div class=\"form-group\">\n                                <label>Name</label>\n                                <input\n                                    type=\"text\"\n                                    id=\"test-name\"\n                                    class=\"form-control\"\n                                    value={this.state.editing_test.name}\n                                    onChange={this.handle_change}\n                                />\n                            </div>\n                            <div class=\"form-group\">\n                                <label>\n                                    Inputs (each test case separated by a new\n                                    line, arguments separated by '|')\n                                </label>\n                                <textarea\n                                    rows=\"5\"\n                                    id=\"test-input\"\n                                    class=\"form-control\"\n                                    value={this.state.editing_test.input}\n                                    onChange={this.handle_change}\n                                ></textarea>\n                            </div>\n                            <div class=\"form-group\">\n                                <label>\n                                    Corresponding outputs (each separated by a\n                                    new line)\n                                </label>\n                                <textarea\n                                    rows=\"5\"\n                                    id=\"test-output\"\n                                    class=\"form-control\"\n                                    value={this.state.editing_test.output}\n                                    onChange={this.handle_change}\n                                ></textarea>\n                            </div>\n                            <button\n                                class=\"btn btn-success btn-sm\"\n                                onClick={this.save_test}\n                            >\n                                Save test\n                            </button>\n                        </div>\n                    )}\n                    <table\n                        id=\"challenges-table\"\n                        class=\"table table-striped table-sm\"\n                    >\n                        <thead>\n                            <tr>\n                                <th style={{ width: '80px' }}></th>\n                                <th>Name</th>\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {!!this.state.tests.length &&\n                                this.state.tests.map((test, index) => {\n                                    test.index = index;\n                                    return (\n                                        <tr key={index}>\n                                            <td class=\"actions\">\n                                                <a\n                                                    onClick={() =>\n                                                        this.manage_test(test)\n                                                    }\n                                                >\n                                                    <i class=\"fa fa-pen green pointer\"></i>\n                                                </a>{' '}\n                                                <a\n                                                    onClick={() =>\n                                                        this.delete_test(index)\n                                                    }\n                                                >\n                                                    <i class=\"fa fa-trash text-danger pointer\"></i>\n                                                </a>\n                                            </td>\n                                            <td>{test.name}</td>\n                                        </tr>\n                                    );\n                                })}\n                        </tbody>\n                    </table>\n                </div>\n\n                <button\n                    type=\"button\"\n                    class=\"btn btn-success\"\n                    onClick={this.save}\n                >\n                    Save challenge\n                </button>\n            </div>\n        );\n    }\n}\n\nUtil.try_render('react_manage_challenge', ManageChallenge);\n\nexport default ManageChallenge;\n"
  },
  {
    "path": "platform/resources/jsx/cli_script.jsx",
    "content": "import React from 'react';\n\nimport Util from 'js/util';\n\nclass CliScript extends React.Component {\n    componentDidMount() {\n        let editor = monaco.editor.create(document.getElementById('editor'), {\n            theme: 'em',\n            value: this.props.content,\n            language: 'shell',\n            automaticLayout: true,\n            fontSize: 16,\n            readOnly: true,\n            wordWrap: 'off',\n            scrollBeyondLastLine: false,\n            scrollbar: {\n                vertical: 'hidden'\n            },\n            minimap: {\n                enabled: false\n            }\n        });\n\n        document.getElementById('editor').style.height =\n            editor.getModel().getLineCount() * 22 + 'px';\n    }\n\n    render() {\n        return <div id=\"editor\"></div>;\n    }\n}\n\nUtil.try_render('react_cli_script', CliScript);\n\nexport default CliScript;\n"
  },
  {
    "path": "platform/resources/jsx/contests/contest.jsx",
    "content": "import React from 'react';\nimport axios from 'axios';\nimport moment from 'moment';\n\nimport Util from 'js/util';\n\nimport Description from './description';\n\nclass Contest extends React.Component {\n    constructor(props) {\n        super(props);\n\n        this.state = {\n            contest: props.contest,\n            language: '',\n            language_version: '',\n            solution: '',\n            explanation: '',\n            languages: [],\n            passed: true,\n            validating: false,\n            submitting: false,\n            shown_submissions: [],\n            showing_late: false,\n            filtered_language: 'all',\n            filtered_language_version: ''\n        };\n\n        this.encoder = new TextEncoder();\n        this.on_time_submissions = [];\n        this.late_submissions = [];\n\n        // choose the right initial on time solution by length\n        let submission = props.submissions\n            .filter((submission) => !submission.late)\n            .sort((a, b) => (a.length > b.length ? 1 : -1))[0];\n\n        if (submission) {\n            this.state.language = submission.language;\n            this.state.language_version = submission.language_version;\n            this.state.solution = submission.solution;\n            this.state.explanation = submission.explanation;\n        }\n\n        if (this.state.contest.submissions.length > 0) {\n            this.on_time_submissions = this.state.contest.submissions.filter(\n                (submission) => !submission.late\n            );\n            this.late_submissions = this.state.contest.submissions.filter(\n                (submission) => submission.late\n            );\n        }\n        this.filter_languages = this.filter_languages.bind(this);\n    }\n\n    highlight_blocks() {\n        $('.ql-syntax').each(function (i, block) {\n            hljs.highlightBlock(block);\n        });\n    }\n\n    async componentDidMount() {\n        this.highlight_blocks();\n\n        let languages = await axios.get('/api/v2/piston/runtimes');\n        let disallowed_languages = await axios.get(\n            '/contests/disallowed_languages/' + this.state.contest.contest_id\n        );\n\n        disallowed_languages = disallowed_languages.data;\n\n        languages = languages.data\n            .sort((a, b) => (a.language < b.language ? -1 : 1))\n            .reduce((a, c) => {\n                if (a.find((l) => l.language === c.language)) {\n                    return a;\n                }\n\n                let tmp = languages.data\n                    .filter((language) => language.language === c.language)\n                    .sort((a, b) => (a.version > b.version ? -1 : 1));\n\n                a.push(tmp[0]);\n\n                return a;\n            }, [])\n            .filter((lang) => !disallowed_languages.includes(lang.language));\n\n        this.setState({\n            languages,\n            language: this.state.language || languages[0].language,\n            language_version:\n                this.state.language_version || languages[0].version,\n            shown_submissions: this.on_time_submissions\n        });\n    }\n\n    handle_change = (e) => {\n        let id = e.target.id;\n        let value = e.target.value;\n\n        if (id === 'language') {\n            let [language, language_version] = value.split('-');\n\n            let submission = this.props.submissions.find((submission) => {\n                return (\n                    submission.language === language &&\n                    submission.language_version === language_version &&\n                    !!submission.late === !this.state.contest.active\n                );\n            });\n\n            this.setState({\n                solution: submission ? submission.solution : '',\n                explanation: submission ? submission.explanation : '',\n                language,\n                language_version\n            });\n        } else {\n            this.setState({\n                [id]: value\n            });\n        }\n    };\n\n    filter_languages = (e) => {\n        let [filtered_language, filtered_language_version] =\n            e.target.value.split('-');\n        if (filtered_language === 'all') {\n            filtered_language_version = '';\n        }\n\n        let shown_submissions = this.state.showing_late\n            ? this.late_submissions\n            : this.on_time_submissions;\n        if (filtered_language != 'all') {\n            shown_submissions = shown_submissions.filter(\n                (submission) =>\n                    submission.language === filtered_language &&\n                    submission.language_version === filtered_language_version\n            );\n        }\n        this.setState({\n            filtered_language,\n            filtered_language_version,\n            shown_submissions\n        });\n    };\n\n    toggle_explanation = (submission) => {\n        submission.explanation_open = !submission.explanation_open;\n\n        this.setState((prev) => {\n            return {\n                shown_submissions: prev.shown_submissions\n            };\n        });\n    };\n\n    set_late = (showing_late) => {\n        // update the main list of submissions\n        let shown_submissions = showing_late\n            ? this.late_submissions\n            : this.on_time_submissions;\n\n        // update the user specific submission\n        let submission = this.props.submissions\n            .filter((submission) =>\n                showing_late ? submission.late : !submission.late\n            )\n            .sort((a, b) => (a.length > b.length ? 1 : -1))[0];\n\n        this.setState((prev) => {\n            return {\n                showing_late,\n                shown_submissions,\n                language: submission ? submission.language : prev.language,\n                language_version: submission\n                    ? submission.language_version\n                    : prev.language_version,\n                solution: submission ? submission.solution : '',\n                explanation: submission ? submission.explanation : '',\n                filtered_language: 'all',\n                filtered_language_version: ''\n            };\n        });\n    };\n\n    submit = async () => {\n        this.setState({\n            passed: true\n        });\n\n        const { language, solution, explanation, language_version } =\n            this.state;\n\n        this.setState({\n            submitting: true\n        });\n\n        let result = await axios.post('/contests/submit', {\n            contest_id: this.state.contest.contest_id,\n            language,\n            solution,\n            explanation,\n            language_version\n        });\n\n        this.setState({\n            submitting: false\n        });\n\n        if (result.status >= 400) {\n            return bootbox.alert('An error has occurred');\n        }\n\n        if (result.data.passed) {\n            return bootbox.alert(\n                'Your solution succeeded and has been recorded/updated.',\n                () => {\n                    location = location;\n                }\n            );\n        }\n\n        this.setState({\n            passed: false\n        });\n    };\n\n    async delete(contest_submission_id) {\n        bootbox.confirm({\n            message: 'Are you sure you want to delete this submission?',\n            buttons: {\n                confirm: {\n                    label: 'Delete',\n                    className: 'btn-danger'\n                },\n                cancel: {\n                    label: 'Cancel',\n                    className: 'btn-secondary'\n                }\n            },\n            callback: async (result) => {\n                if (!result) {\n                    return;\n                }\n\n                let res = await axios.post('/admin/submissions/delete', {\n                    contest_submission_id\n                });\n\n                location = location;\n            }\n        });\n    }\n\n    validate = async () => {\n        this.setState({\n            validating: true\n        });\n\n        let res = await axios.post(\n            '/admin/submissions/validate/' + this.state.contest.contest_id\n        );\n\n        let { invalids } = res.data;\n\n        this.setState({\n            validating: false\n        });\n\n        if (!invalids.length) {\n            return bootbox.alert('No invalid submissions were found');\n        }\n\n        let invalids_str = '';\n\n        for (let invalid of invalids) {\n            invalids_str += `(#${invalid.contest_submission_id}) ${invalid.user.username}'s ${invalid.language}\\\n            submission of length ${invalid.length}<br />`;\n        }\n\n        return bootbox.alert(\n            'The following invalid submissions were found:<br />' + invalids_str\n        );\n    };\n\n    render() {\n        const active = this.state.contest.active;\n\n        return (\n            <div class=\"em_contests_contest\">\n                <h4 class=\"header green f500 marginbottom20\">\n                    {this.state.contest.name}\n                </h4>\n\n                <Description description={this.state.contest.description} />\n\n                <h5 class=\"green marginbottom10\">Test Cases</h5>\n                <div class=\"marginbottom20\">\n                    {this.props.cases.map((c, i) => {\n                        return (\n                            <div key={'test-' + i}>\n                                <h6>Test Case {i + 1}</h6>\n                                <pre class=\"case_text\">\n                                    {c.hide_input &&\n                                    (active || c.hide_ignore_active) ? (\n                                        <strong>\n                                            {c.args.length} hidden argument(s)\n                                        </strong>\n                                    ) : (\n                                        c.args.map((input, i) => {\n                                            return (\n                                                <div key={'input-' + i}>\n                                                    <strong>\n                                                        Argument {i + 1}\n                                                    </strong>\n                                                    {'\\n'}\n                                                    {input}\n                                                    {'\\n'}\n                                                </div>\n                                            );\n                                        })\n                                    )}\n                                    {'\\n'}\n                                    {c.hide_output &&\n                                    (active || c.hide_ignore_active) ? (\n                                        <strong>Hidden Output</strong>\n                                    ) : (\n                                        <>\n                                            <strong>Expected Output</strong>\n                                            {'\\n'}\n                                            {c.output.replace(/\\\\n/g, '\\n')}\n                                        </>\n                                    )}\n                                </pre>\n                            </div>\n                        );\n                    })}\n                </div>\n\n                <h5 class=\"green\">Your Submission</h5>\n                <div class=\"marginbottom20\">\n                    {(ctx.user_id && (\n                        <div>\n                            {((active || this.state.showing_late) && (\n                                <>\n                                    <p>\n                                        It's recommended that you compose your\n                                        solution separately and just paste here\n                                        once you're ready. After clicking\n                                        \"Submit Solution\" your solution will be\n                                        tested with the given inputs. If\n                                        successful, your solution will be saved.\n                                        Be sure to choose the correct language.\n                                    </p>\n                                    <div class=\"form-group\">\n                                        <label class=\"green\">Language</label>\n                                        <select\n                                            id=\"language\"\n                                            class=\"form-control\"\n                                            style={{ width: '300px' }}\n                                            value={\n                                                this.state.language +\n                                                '-' +\n                                                this.state.language_version\n                                            }\n                                            onChange={this.handle_change}\n                                        >\n                                            {this.state.languages.map(\n                                                (language) => {\n                                                    return (\n                                                        <option\n                                                            key={\n                                                                language.language +\n                                                                '-' +\n                                                                language.version\n                                                            }\n                                                            value={\n                                                                language.language +\n                                                                '-' +\n                                                                language.version\n                                                            }\n                                                        >\n                                                            {language.language}{' '}\n                                                            (\n                                                            {language.runtime\n                                                                ? `via ${language.runtime} `\n                                                                : ''}\n                                                            {language.version})\n                                                        </option>\n                                                    );\n                                                }\n                                            )}\n                                        </select>\n                                    </div>\n                                    {this.props.submissions &&\n                                        this.props.submissions.length > 0 && (\n                                            <div class=\"form-group\">\n                                                <small>\n                                                    You have solutions in:{' '}\n                                                    {this.props.submissions\n                                                        .filter((s) =>\n                                                            this.state\n                                                                .showing_late\n                                                                ? s.late\n                                                                : !s.late\n                                                        )\n                                                        .map(\n                                                            (submission, i) => {\n                                                                return (\n                                                                    <span\n                                                                        key={\n                                                                            submission.language +\n                                                                            '-' +\n                                                                            submission.late\n                                                                        }\n                                                                    >\n                                                                        {\n                                                                            submission.language\n                                                                        }{' '}\n                                                                        (\n                                                                        {\n                                                                            submission.length\n                                                                        }\n                                                                        )\n                                                                        {i + 1 <\n                                                                            this\n                                                                                .props\n                                                                                .submissions\n                                                                                .length &&\n                                                                            ', '}\n                                                                    </span>\n                                                                );\n                                                            }\n                                                        )}\n                                                </small>\n                                            </div>\n                                        )}\n                                    <div class=\"form-group\">\n                                        <label class=\"green\">Solution</label>\n                                        <textarea\n                                            id=\"solution\"\n                                            rows=\"6\"\n                                            class=\"form-control text-monospace\"\n                                            value={this.state.solution}\n                                            onChange={this.handle_change}\n                                        ></textarea>\n                                        <span\n                                            class=\"margintop5\"\n                                            style={{\n                                                display: 'flex',\n                                                'justify-content': 'end'\n                                            }}\n                                        >\n                                            {\n                                                this.encoder.encode(\n                                                    this.state.solution.trim()\n                                                ).length\n                                            }{' '}\n                                            bytes\n                                        </span>\n                                    </div>\n                                    <div class=\"form-group\">\n                                        <label class=\"green\">\n                                            (Optional) Share your knowledge!\n                                        </label>\n                                        <br />\n                                        <label>\n                                            Explain your solution so others can\n                                            understand it when the contest is\n                                            over.\n                                        </label>\n                                        <textarea\n                                            id=\"explanation\"\n                                            rows=\"6\"\n                                            class=\"form-control text-monospace\"\n                                            value={this.state.explanation}\n                                            onChange={this.handle_change}\n                                        ></textarea>\n                                    </div>\n                                    <div class=\"form-group\">\n                                        <button\n                                            type=\"button\"\n                                            class=\"btn btn-sm btn-success\"\n                                            disabled={this.state.submitting}\n                                            onClick={this.submit}\n                                        >\n                                            {this.state.submitting\n                                                ? 'Submitting...'\n                                                : 'Submit Solution'}\n                                        </button>{' '}\n                                        {!this.state.passed && (\n                                            <span class=\"text-danger\">\n                                                Sorry, your solution does not\n                                                satisfy the requirements\n                                            </span>\n                                        )}\n                                    </div>\n                                </>\n                            )) || (\n                                <p class=\"text-warning\">\n                                    This contest is no longer active but you can\n                                    still submit a late solution. Click on the\n                                    \"Late\" tab below and then submit as usual.\n                                    Note that late submissions will not receive\n                                    any points.\n                                </p>\n                            )}\n                        </div>\n                    )) || (\n                        <div>\n                            You are not logged in. To submit a solution, click\n                            the Login button at the top right.\n                        </div>\n                    )}\n                </div>\n\n                <h5 class=\"green marginbottom20\">Submissions</h5>\n                <div class=\"space-between marginbottom10\">\n                    <select\n                        id=\"language-filter\"\n                        class=\"form-control\"\n                        style={{ width: '300px' }}\n                        value={\n                            this.state.filtered_language +\n                            '-' +\n                            this.state.filtered_language_version\n                        }\n                        onChange={this.filter_languages}\n                    >\n                        <option key=\"all\" value=\"all\">\n                            All\n                        </option>\n                        {this.state.languages.map((language) => {\n                            return (\n                                <option\n                                    key={\n                                        language.language +\n                                        '-' +\n                                        language.version\n                                    }\n                                    value={\n                                        language.language +\n                                        '-' +\n                                        language.version\n                                    }\n                                >\n                                    {language.language} (\n                                    {language.runtime\n                                        ? `via ${language.runtime} `\n                                        : ''}\n                                    {language.version})\n                                </option>\n                            );\n                        })}\n                    </select>\n                    {!!ctx.is_staff && (\n                        <div class=\"float-right\">\n                            <button\n                                type=\"button\"\n                                class=\"btn btn-sm btn-warning\"\n                                disabled={this.state.validating}\n                                onClick={this.validate}\n                            >\n                                {this.state.validating\n                                    ? 'Re-validating...'\n                                    : 'Re-validate submissions'}\n                            </button>{' '}\n                        </div>\n                    )}\n                </div>\n                {!active && (\n                    <ul class=\"nav nav-tabs\">\n                        <li class=\"nav-item\">\n                            <a\n                                class={\n                                    this.state.showing_late\n                                        ? 'pointer nav-link'\n                                        : 'pointer nav-link tab-active'\n                                }\n                                onClick={() => this.set_late(false)}\n                            >\n                                On time\n                            </a>\n                        </li>\n                        <li class=\"nav-item\">\n                            <a\n                                class={\n                                    this.state.showing_late\n                                        ? 'pointer nav-link tab-active'\n                                        : 'pointer nav-link'\n                                }\n                                onClick={() => this.set_late(true)}\n                            >\n                                Late\n                            </a>\n                        </li>\n                    </ul>\n                )}\n                {this.state.shown_submissions.map((submission) => {\n                    return (\n                        <div\n                            key={submission.contest_submission_id}\n                            class=\"submission\"\n                        >\n                            <div class=\"heading\">\n                                <div class=\"main\">\n                                    <div class=\"summary\">\n                                        {submission.length} bytes with{' '}\n                                        {submission.language}{' '}\n                                        {submission.overall_first && (\n                                            <img src=\"/images/awards/1.png\" />\n                                        )}{' '}\n                                        {submission.overall_second && (\n                                            <img src=\"/images/awards/2.png\" />\n                                        )}{' '}\n                                        {submission.overall_third && (\n                                            <img src=\"/images/awards/3.png\" />\n                                        )}{' '}\n                                        {submission.language_first && (\n                                            <img src=\"/images/awards/4.png\" />\n                                        )}\n                                    </div>\n                                    <div class=\"time\">\n                                        Submitted:{' '}\n                                        {moment(submission.created_at).format(\n                                            'MMMM D, YYYY @ h:mm:ss a'\n                                        )}{' '}\n                                        (#{submission.contest_submission_id}){' '}\n                                        {!!ctx.is_staff && (\n                                            <a\n                                                onClick={() =>\n                                                    this.delete(\n                                                        submission.contest_submission_id\n                                                    )\n                                                }\n                                                class=\"fas fa-trash text-danger pointer\"\n                                            ></a>\n                                        )}\n                                    </div>\n                                    {!active && !!submission.explanation && (\n                                        <div\n                                            id={\n                                                submission.contest_submission_id\n                                            }\n                                            class=\"explanation_text pointer green\"\n                                            onClick={() =>\n                                                this.toggle_explanation(\n                                                    submission\n                                                )\n                                            }\n                                        >\n                                            {submission.explanation_open\n                                                ? 'Hide'\n                                                : 'Show'}{' '}\n                                            Explanation\n                                        </div>\n                                    )}\n                                </div>\n                                <a\n                                    href={'/@' + submission.user.username}\n                                    class=\"user\"\n                                >\n                                    <img\n                                        src={\n                                            ctx.cdn_url +\n                                            submission.user.avatar_url\n                                        }\n                                    />{' '}\n                                    {submission.user.username}\n                                </a>\n                            </div>\n                            {!active && (\n                                <pre class=\"solution\">\n                                    {submission.solution}\n                                </pre>\n                            )}\n                            {!active && !!submission.explanation_open && (\n                                <div class=\"margintop10\">\n                                    <small class=\"green\">\n                                        The following explanation was provided:\n                                    </small>\n                                    <pre class=\"solution\">\n                                        {submission.explanation}\n                                    </pre>\n                                </div>\n                            )}\n                        </div>\n                    );\n                })}\n            </div>\n        );\n    }\n}\n\nUtil.try_render('react_contest_contest', Contest);\n\nexport default Contest;\n"
  },
  {
    "path": "platform/resources/jsx/contests/description.jsx",
    "content": "import React from 'react';\nimport Quill from 'quill';\n\nclass Description extends React.PureComponent {\n    ops_to_html(ops) {\n        try {\n            ops = JSON.parse(ops).ops;\n            var tmp = document.createElement('div');\n            new Quill(tmp, { modules: { syntax: true } }).setContents(ops);\n            return tmp.getElementsByClassName('ql-editor')[0].innerHTML;\n        } catch (e) {\n            return '';\n        }\n    }\n\n    render() {\n        return (\n            <div class=\"ql-snow marginbottom20\">\n                <div\n                    class=\"ql-editor\"\n                    dangerouslySetInnerHTML={{\n                        __html: this.ops_to_html(this.props.description)\n                    }}\n                ></div>\n            </div>\n        );\n    }\n}\n\nexport default Description;\n"
  },
  {
    "path": "platform/resources/jsx/contests/manage.jsx",
    "content": "import React from 'react';\nimport axios from 'axios';\nimport Quill from 'quill';\n\nimport Util from 'js/util';\n\nclass Manage extends React.Component {\n    constructor(props) {\n        super(props);\n\n        this.state = {\n            ...props.contest,\n            languages: []\n        };\n    }\n\n    async componentDidMount() {\n        this.quill = new Quill('#description', {\n            theme: 'snow',\n            modules: {\n                syntax: true,\n                toolbar: [\n                    ['bold', 'italic', 'underline', 'strike'],\n                    ['blockquote', 'code-block', 'link'],\n                    [{ header: 1 }, { header: 2 }],\n                    [{ list: 'ordered' }, { list: 'bullet' }],\n                    ['clean']\n                ]\n            }\n        });\n\n        if (this.props.mode === 'update') {\n            this.quill.setContents(JSON.parse(this.state.description));\n        }\n\n        let disallowed_languages = this.state.disallowed_languages\n            ? this.state.disallowed_languages.split(',')\n            : [];\n\n        let { data: languages } = await axios.get('/api/v2/piston/runtimes');\n\n        languages = languages\n            .sort((a, b) => (a.language < b.language ? -1 : 1))\n            .reduce((a, c) => {\n                c.enabled = !disallowed_languages.includes(c.language);\n\n                if (a.find((l) => l.language === c.language)) {\n                    return a;\n                }\n\n                let tmp = languages\n                    .filter((language) => language.language === c.language)\n                    .sort((a, b) => (a.version > b.version ? -1 : 1));\n\n                a.push(tmp[0]);\n\n                return a;\n            }, []);\n\n        this.setState({\n            disallowed_languages,\n            languages\n        });\n    }\n\n    handle_change = (e) => {\n        let id = e.target.id;\n        let value = e.target.value;\n        this.setState({\n            [id]: value\n        });\n    };\n\n    handle_language_change = (e) => {\n        e.persist();\n\n        let name = e.target.id;\n\n        this.setState((prev) => {\n            const languages = prev.languages.map((language) => {\n                if (language.language === name) {\n                    language.enabled = e.target.checked;\n                }\n\n                return language;\n            });\n\n            return {\n                languages\n            };\n        });\n    };\n\n    select = (all) => {\n        this.setState((prev) => {\n            const languages = prev.languages.map((language) => {\n                language.enabled = all ? true : !language.enabled;\n\n                return language;\n            });\n\n            return {\n                languages\n            };\n        });\n    };\n\n    save = async () => {\n        let {\n            name,\n            start_date,\n            end_date,\n            input,\n            output,\n            disallowed_languages\n        } = this.state;\n\n        const description = JSON.stringify(this.quill.getContents());\n\n        if (!Util.are_test_cases_valid({ input, output })) {\n            return bootbox.alert('Invalid test cases');\n        }\n\n        const url =\n            this.props.mode === 'update'\n                ? '/admin/contests/update/' + this.props.contest_id\n                : '/admin/contests/create';\n\n        disallowed_languages = this.state.languages\n            .filter((language) => !language.enabled)\n            .map((language) => language.language)\n            .concat(this.props.languages.disallowed_languages)\n            .join(',');\n\n        const res = await axios.post(url, {\n            name,\n            description,\n            start_date,\n            end_date,\n            input,\n            output,\n            disallowed_languages\n        });\n\n        if (res.status === 400) {\n            return bootbox.alert(res.data.message);\n        }\n\n        if (res.status >= 400) {\n            return bootbox.alert('An error has occurred');\n        }\n\n        location = '/admin/contests';\n    };\n\n    render() {\n        return (\n            <div class=\"em_contest_manage\">\n                <div class=\"wrapper\">\n                    <div class=\"left\">\n                        <div class=\"form-group\">\n                            <label>Name</label>\n                            <input\n                                type=\"text\"\n                                id=\"name\"\n                                class=\"form-control\"\n                                value={this.state.name}\n                                onChange={this.handle_change}\n                            />\n                        </div>\n\n                        <div class=\"form-group\">\n                            <label>Description</label>\n                            <div id=\"description\"></div>\n                        </div>\n\n                        <div class=\"form-group\">\n                            <label>Start Date</label>\n                            <input\n                                type=\"text\"\n                                id=\"start_date\"\n                                class=\"form-control\"\n                                value={this.state.start_date}\n                                onChange={this.handle_change}\n                            />\n                        </div>\n\n                        <div class=\"form-group\">\n                            <label>End Date</label>\n                            <input\n                                type=\"text\"\n                                id=\"end_date\"\n                                class=\"form-control\"\n                                value={this.state.end_date}\n                                onChange={this.handle_change}\n                            />\n                        </div>\n\n                        <div class=\"form-group\">\n                            <label>\n                                Input(s) (Each test case on a new line, multiple\n                                inputs are separated by |)\n                            </label>\n                            <textarea\n                                id=\"input\"\n                                class=\"form-control\"\n                                rows=\"4\"\n                                value={this.state.input}\n                                onChange={this.handle_change}\n                            ></textarea>\n                        </div>\n\n                        <div class=\"form-group\">\n                            <label>\n                                Output(s) (Each test case result on a new line)\n                            </label>\n                            <textarea\n                                id=\"output\"\n                                class=\"form-control\"\n                                rows=\"4\"\n                                value={this.state.output}\n                                onChange={this.handle_change}\n                            ></textarea>\n                        </div>\n\n                        <div class=\"form-group\">\n                            <button\n                                type=\"button\"\n                                class=\"btn btn-sm btn-success\"\n                                onClick={this.save}\n                            >\n                                Save\n                            </button>\n                        </div>\n                    </div>\n                    <div class=\"right\">\n                        <div class=\"form-group\">\n                            <label>Allowed languages</label>\n\n                            <div>\n                                <button\n                                    type=\"button\"\n                                    class=\"btn btn-sm btn-secondary\"\n                                    onClick={() => this.select(true)}\n                                >\n                                    All\n                                </button>{' '}\n                                <button\n                                    type=\"button\"\n                                    class=\"btn btn-sm btn-secondary\"\n                                    onClick={() => this.select(false)}\n                                >\n                                    Invert\n                                </button>\n                            </div>\n\n                            {this.state.languages.map((lang) => {\n                                return (\n                                    <div key={lang.language}>\n                                        <input\n                                            type=\"checkbox\"\n                                            id={lang.language}\n                                            checked={lang.enabled}\n                                            onChange={\n                                                this.handle_language_change\n                                            }\n                                        />{' '}\n                                        {lang.language} (\n                                        {lang.runtime\n                                            ? `via ${lang.runtime} `\n                                            : ''}\n                                        {lang.version})\n                                    </div>\n                                );\n                            })}\n                        </div>\n                    </div>\n                </div>\n            </div>\n        );\n    }\n}\n\nUtil.try_render('react_contest_manage', Manage);\n\nexport default Manage;\n"
  },
  {
    "path": "platform/resources/jsx/login.jsx",
    "content": "import React from 'react';\n\nimport Util from 'js/util';\n\nclass Login extends React.Component {\n    constructor(props) {\n        super(props);\n\n        this.state = {\n            open: false\n        };\n\n        this.open = this.open.bind(this);\n        this.close = this.close.bind(this);\n    }\n\n    open(redirect) {\n        this.setState({\n            open: true,\n            redirect: redirect || location.pathname\n        });\n    }\n\n    close() {\n        this.setState({\n            open: false\n        });\n    }\n\n    render() {\n        return (\n            <div class={'em_login ' + (this.state.open ? 'open' : '')}>\n                <div class=\"backdrop\">\n                    <div class=\"box\">\n                        <div class=\"close\" onClick={this.close}>\n                            <i class=\"fa fa-times\"></i>\n                        </div>\n                        <h4>Login/Register</h4>\n                        <p>At the moment only Discord login is supported.</p>\n                        <a\n                            href={\n                                '/auth/discord' +\n                                (this.state.redirect\n                                    ? '?r=' + this.state.redirect\n                                    : '')\n                            }\n                            class=\"btn btn-block\"\n                        >\n                            Login with Discord\n                        </a>\n                    </div>\n                </div>\n            </div>\n        );\n    }\n}\n\nwindow.login = Util.try_render('react_login', Login);\n\nexport default Login;\n"
  },
  {
    "path": "platform/resources/jsx/manage_snippet.jsx",
    "content": "import React from 'react';\nimport axios from 'axios';\n\nimport Util from 'js/util';\n\nclass ManageSnippet extends React.Component {\n    constructor(props) {\n        super(props);\n        this.state = {\n            snip: this.props.mode === 'create' ? '' : this.props.snip,\n            language:\n                this.props.mode === 'create'\n                    ? 'javascript'\n                    : this.props.language,\n            word_wrap: 'off',\n            runnable_language: false,\n            executing: false,\n            stdin: '',\n            argv: '',\n            compile_output: '',\n            stdout: '',\n            stderr: ''\n        };\n\n        this.monaco_piston_map = {\n            abap: 'none',\n            aes: 'none',\n            apex: 'none',\n            awk: 'awk',\n            azcli: 'none',\n            bat: 'none',\n            bicep: 'none',\n            c: 'c',\n            cameligo: 'none',\n            cjam: 'cjam',\n            clojure: 'clojure',\n            cobol: 'cobol',\n            coffeescript: 'coffeescript',\n            cow: 'cow',\n            cpp: 'cpp',\n            crystal: 'crystal',\n            csharp: 'csharp',\n            csp: 'none',\n            css: 'none',\n            d: 'd',\n            dart: 'dart',\n            dash: 'dash',\n            dockerfile: 'none',\n            dragon: 'dragon',\n            ecl: 'none',\n            elixir: 'elixir',\n            emacs: 'emacs',\n            erlang: 'erlang',\n            fortran: 'fortran',\n            fsharp: 'fsharp.net',\n            go: 'go',\n            golfscript: 'golfscript',\n            graphql: 'none',\n            groovy: 'groovy',\n            handlebars: 'none',\n            haskell: 'haskell',\n            hcl: 'none',\n            html: 'none',\n            ini: 'none',\n            java: 'java',\n            javascript: 'javascript',\n            jelly: 'jelly',\n            json: 'none',\n            julia: 'julia',\n            kotlin: 'kotlin',\n            less: 'none',\n            lexon: 'none',\n            liquid: 'none',\n            lisp: 'lisp',\n            lua: 'lua',\n            lolcode: 'lolcode',\n            m3: 'none',\n            markdown: 'none',\n            mips: 'none',\n            msdax: 'none',\n            mysql: 'none',\n            sql: 'sqlite',\n            'objective-c': 'none',\n            nasm: 'nasm',\n            nasm64: 'nasm64',\n            nim: 'nim',\n            ocaml: 'ocaml',\n            octave: 'octave',\n            osabie: 'osabie',\n            paradoc: 'paradoc',\n            pascal: 'pascal',\n            pascaligo: 'none',\n            perl: 'perl',\n            pgsql: 'none',\n            php: 'php',\n            plaintext: 'none',\n            ponylang: 'ponylang',\n            postiats: 'none',\n            powerquery: 'none',\n            powershell: 'powershell',\n            prolog: 'prolog',\n            pure: 'pure',\n            pug: 'none',\n            pyth: 'pyth',\n            python: 'python',\n            python2: 'python2',\n            qsharp: 'none',\n            r: 'r',\n            raku: 'raku',\n            razor: 'none',\n            redis: 'none',\n            redshift: 'none',\n            restructuredtext: 'none',\n            rockstar: 'rockstar',\n            ruby: 'ruby',\n            rust: 'rust',\n            sb: 'none',\n            scala: 'scala',\n            scheme: 'none',\n            scss: 'none',\n            shell: 'bash',\n            sol: 'none',\n            sparql: 'none',\n            st: 'none',\n            swift: 'swift',\n            systemverilog: 'none',\n            tcl: 'none',\n            twig: 'none',\n            typescript: 'typescript',\n            vb: 'vb',\n            verilog: 'none',\n            vlang: 'vlang',\n            xml: 'none',\n            yaml: 'none',\n            yeethon: 'yeethon',\n            zig: 'zig'\n        };\n\n        this.change_language = this.change_language.bind(this);\n        this.handle_change = this.handle_change.bind(this);\n        this.execute = this.execute.bind(this);\n        this.toggle_word_wrap = this.toggle_word_wrap.bind(this);\n        this.save = this.save.bind(this);\n    }\n\n    componentDidMount() {\n        this.state.editor = monaco.editor.create(\n            document.getElementById('editor'),\n            {\n                theme: 'em',\n                language: this.state.language,\n                automaticLayout: true,\n                value: this.state.snip,\n                readOnly: this.props.mode === 'view',\n                fontSize: 16\n            }\n        );\n        this.props.mode !== 'view' &&\n            this.state.editor.addCommand(\n                monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S,\n                this.save\n            );\n        this.state.editor.addCommand(monaco.KeyCode.F9, this.execute);\n        this.check_runnable_language();\n    }\n\n    check_runnable_language() {\n        this.setState({\n            runnable_language:\n                this.state.language in this.monaco_piston_map &&\n                this.monaco_piston_map[this.state.language] !== 'none'\n        });\n    }\n\n    async execute() {\n        if (!this.state.runnable_language) {\n            return;\n        }\n        this.setState({\n            executing: true\n        });\n        const result = await axios.post('/api/v2/piston/execute', {\n            language: this.state.language,\n            version: '*',\n            files: [{ content: this.state.editor.getValue() }],\n            args: this.state.argv === '' ? [] : this.state.argv.split('\\n'),\n            stdin: this.state.stdin\n        });\n        this.setState({\n            executing: false\n        });\n        if (result.status === 429) {\n            return bootbox.alert(\n                'You are executing the snippet too many times.'\n            );\n        }\n        if (result.status >= 400) {\n            return bootbox.alert('An internal error has occurred.');\n        }\n        // Check if it is a compiled language\n        const compile_output =\n            'compile' in result.data ? result.data.compile.output : '';\n        const { stdout, stderr } = result.data.run;\n        this.setState({ compile_output, stdout, stderr });\n    }\n\n    handle_change(e) {\n        this.setState({\n            [e.target.id]: e.target.value\n        });\n    }\n\n    change_language(event) {\n        this.setState(\n            {\n                language: event.target.value\n            },\n            this.check_runnable_language\n        );\n\n        monaco.editor.setModelLanguage(\n            this.state.editor.getModel(),\n            event.target.value\n        );\n    }\n\n    toggle_word_wrap() {\n        const word_wrap = this.state.word_wrap === 'off' ? 'bounded' : 'off';\n        this.state.editor.updateOptions({\n            wordWrap: word_wrap\n        });\n        this.setState({\n            word_wrap\n        });\n    }\n\n    async save() {\n        const url =\n            this.props.mode === 'update'\n                ? '/snippets/edit/' + this.props.hash\n                : '/snippets';\n        const res = await axios.post(url, {\n            language: this.state.language,\n            snip: this.state.editor.getValue()\n        });\n\n        if (res.status >= 300) {\n            return bootbox.alert('Please provide some code');\n        }\n\n        location = res.data.url;\n    }\n\n    render() {\n        return (\n            <div class=\"em_manage_snippet\">\n                <div class=\"menu\">\n                    <div class=\"wrapper\">\n                        <div class=\"language\">\n                            {(this.props.mode !== 'view' && (\n                                <select\n                                    onChange={this.change_language}\n                                    defaultValue={this.state.language}\n                                    class=\"form-control\"\n                                >\n                                    {Object.keys(this.monaco_piston_map).map(\n                                        (language) => {\n                                            return (\n                                                <option key={language}>\n                                                    {language}\n                                                </option>\n                                            );\n                                        }\n                                    )}\n                                </select>\n                            )) || (\n                                <>\n                                    <span class=\"language_label f700\">\n                                        Language:\n                                    </span>\n                                    {this.props.language}\n                                </>\n                            )}\n                        </div>\n                        <div>\n                            <button\n                                type=\"button\"\n                                title=\"Toggle word wrap\"\n                                class=\"btn btn-md btn-dark control-button\"\n                                onClick={this.toggle_word_wrap}\n                            >\n                                Wrap\n                            </button>\n                            {this.state.runnable_language && (\n                                <button\n                                    type=\"button\"\n                                    title=\"Run the code (F9)\"\n                                    class=\"btn btn-md btn-primary control-button\"\n                                    disabled={this.state.executing}\n                                    onClick={this.execute}\n                                >\n                                    <i class=\"fas fa-play\"></i>\n                                </button>\n                            )}\n                            {(this.props.mode !== 'view' && (\n                                <button\n                                    type=\"button\"\n                                    title=\"Save the snippet (Ctrl + S)\"\n                                    class=\"btn btn-md btn-success control-button\"\n                                    onClick={this.save}\n                                >\n                                    <i class=\"fas fa-save\"></i>\n                                </button>\n                            )) ||\n                                (ctx.user_id === this.props.user_id && (\n                                    <button\n                                        type=\"button\"\n                                        title=\"Edit the snippet\"\n                                        class=\"btn btn-md btn-success control-button\"\n                                        onClick={() => {\n                                            location = `/snippets/edit/${this.props.hash}`;\n                                        }}\n                                    >\n                                        <i class=\"fas fa-pen\"></i>\n                                    </button>\n                                ))}\n                        </div>\n                    </div>\n                </div>\n                <div\n                    id=\"editor\"\n                    style={\n                        this.state.runnable_language ? { height: '55vh' } : {}\n                    }\n                ></div>\n                {this.state.runnable_language && (\n                    <div class=\"run-data text-monospace\">\n                        <div class=\"inputs-outputs\">\n                            <div class=\"form-group\">\n                                <label>Standard Input</label>\n                                <textarea\n                                    id=\"stdin\"\n                                    class=\"form-control\"\n                                    rows=\"4\"\n                                    onChange={this.handle_change}\n                                ></textarea>\n                            </div>\n                            <div class=\"form-group\">\n                                <label>\n                                    Command-line arguments (separated by a new\n                                    line)\n                                </label>\n                                <textarea\n                                    id=\"argv\"\n                                    class=\"form-control\"\n                                    rows=\"4\"\n                                    onChange={this.handle_change}\n                                ></textarea>\n                            </div>\n                        </div>\n                        <div class=\"inputs-outputs\">\n                            <label>Compile Output</label>\n                            <div class=\"info\">\n                                <pre>{this.state.compile_output}</pre>\n                            </div>\n                            <label>Standard Output</label>\n                            <div class=\"info\">\n                                <pre>{this.state.stdout}</pre>\n                            </div>\n                            <label>Standard Error</label>\n                            <div class=\"info\">\n                                <pre>{this.state.stderr}</pre>\n                            </div>\n                        </div>\n                    </div>\n                )}\n            </div>\n        );\n    }\n}\n\nUtil.try_render('react_manage_snippet', ManageSnippet);\n\nexport default ManageSnippet;\n"
  },
  {
    "path": "platform/resources/jsx/mobile_nav.jsx",
    "content": "import React from 'react';\n\nimport Util from 'js/util';\n\nclass MobileNav extends React.Component {\n    constructor(props) {\n        super(props);\n\n        this.state = {\n            open: false\n        };\n\n        this.open = this.open.bind(this);\n        this.close = this.close.bind(this);\n    }\n\n    open(redirect) {\n        this.setState({\n            open: true\n        });\n    }\n\n    close() {\n        this.setState({\n            open: false\n        });\n    }\n\n    render() {\n        return (\n            <div class={'em_mobile_nav ' + (this.state.open ? 'open' : '')}>\n                <div class=\"backdrop\" onClick={this.close}></div>\n                <div class=\"menu\">\n                    <div class=\"contents\">\n                        <i\n                            class=\"fa fa-bars pointer marginbottom20\"\n                            onClick={this.close}\n                        ></i>\n                        <h5 class=\"f300\">Main Menu</h5>\n                        <a href=\"/\">Home</a>\n                        <a href=\"/challenges\">Challenges</a>\n                        <a href=\"/contests\">Contests</a>\n                        <a href=\"/community\">Community</a>\n                        <a href=\"/snippets\">Tools - Snippets</a>\n                        {(ctx.user_id && (\n                            <>\n                                <div class=\"spacer\"></div>\n                                <h5 class=\"f300\">You</h5>\n                                <a href={'/@' + ctx.username}>Profile</a>\n                                <a href=\"/logout\">Logout</a>\n                            </>\n                        )) ||\n                            null}\n                    </div>\n                </div>\n            </div>\n        );\n    }\n}\n\nwindow.mobile_nav = Util.try_render('react_mobile_nav', MobileNav);\n\nexport default MobileNav;\n"
  },
  {
    "path": "platform/resources/jsx/ppman.jsx",
    "content": "import React from 'react';\nimport axios from 'axios';\n\nimport Util from 'js/util';\n\nclass PistonPackageManager extends React.Component {\n    constructor(props) {\n        super(props);\n\n        this.state = {\n            packages: [],\n            message: props.message\n        };\n    }\n\n    async componentDidMount() {\n        let { data: packages } = await axios.get('/admin/piston/packages');\n\n        this.setState({\n            packages\n        });\n    }\n\n    render() {\n        return (\n            <div>\n                <h1>{this.state.message}</h1>\n                <table class=\"table table-sm table-dark\">\n                    <tr>\n                        <th style={{ width: '100px' }}></th>\n                        <th>Name</th>\n                        <th>Version</th>\n                        <th>Installed</th>\n                    </tr>\n                    {this.state.packages.map((pkg) => {\n                        return (\n                            <tr>\n                                <td>\n                                    {(pkg.installed && (\n                                        <a\n                                            key={\n                                                pkg.language +\n                                                '-' +\n                                                pkg.language_version\n                                            }\n                                            href={`/admin/piston/uninstall?language=${pkg.language}&version=${pkg.language_version}`}\n                                            class=\"user_row marginbottom20\"\n                                        >\n                                            Uninstall\n                                        </a>\n                                    )) || (\n                                        <a\n                                            key={\n                                                pkg.language +\n                                                '-' +\n                                                pkg.language_version\n                                            }\n                                            href={`/admin/piston/install?language=${pkg.language}&version=${pkg.language_version}`}\n                                            class=\"user_row marginbottom20\"\n                                        >\n                                            Install\n                                        </a>\n                                    )}\n                                </td>\n                                <td>{pkg.language}</td>\n                                <td>{pkg.language_version}</td>\n                                <td>{pkg.installed ? 'Yes' : 'No'}</td>\n                            </tr>\n                        );\n                    })}\n                </table>\n            </div>\n        );\n    }\n}\n\nUtil.try_render('react_ppman', PistonPackageManager);\n\nexport default PistonPackageManager;\n"
  },
  {
    "path": "platform/resources/jsx/stickers.jsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport axios from 'axios';\n\nimport Util from 'js/util';\n\nclass Stickers extends React.Component {\n    constructor(props) {\n        super(props);\n\n        this.state = {\n            done: false,\n            valid: false,\n            discounted: false,\n            env: props.env || 'sandbox',\n            quantity: props.options[1].quantity,\n            name: '',\n            email: '',\n            address: '',\n            coupon: ''\n        };\n\n        this.handle_update = this.handle_update.bind(this);\n        this.check_coupon = this.check_coupon.bind(this);\n        this.submit = this.submit.bind(this);\n\n        this.check_coupon_timer = null;\n    }\n\n    componentDidMount() {\n        paypal.Button.render(\n            {\n                env: this.props.env,\n                client: {\n                    sandbox: this.props.paypal_id,\n                    production: this.props.paypal_id\n                },\n                locale: 'en_US',\n                style: {\n                    size: 'medium',\n                    color: 'blue',\n                    shape: 'rect',\n                    tagline: false\n                },\n                commit: true,\n                payment: (data, actions) => {\n                    return actions.payment.create({\n                        transactions: [\n                            {\n                                amount: {\n                                    total: this.props.options.find(\n                                        (option) =>\n                                            option.quantity ===\n                                            this.state.quantity\n                                    ).cost,\n                                    currency: 'USD'\n                                },\n                                description:\n                                    this.state.quantity +\n                                    ' 2\" x 2\" Engineer Man Stickers'\n                            }\n                        ]\n                    });\n                },\n                onAuthorize: async (data, actions) => {\n                    return actions.payment.execute().then(async (details) => {\n                        let res = await axios.post('/stickers/order', {\n                            tx: details.transactions[0].related_resources[0]\n                                .sale.id,\n                            quantity: this.state.quantity,\n                            name: this.state.name,\n                            email: this.state.email,\n                            address: this.state.address,\n                            coupon: null\n                        });\n\n                        return bootbox.alert(\n                            'Your order was placed successfully, thanks. Please ' +\n                                'reference Order ID #' +\n                                res.data.order_id +\n                                ' if necessary.',\n                            () => {\n                                location = location;\n                            }\n                        );\n                    });\n                }\n            },\n            '#paypal-button'\n        );\n    }\n\n    handle_update(e) {\n        e.persist();\n\n        this.setState(\n            {\n                [e.target.id]: e.target.value\n            },\n            () => {\n                if (e.target.id === 'coupon') {\n                    this.check_coupon();\n                }\n\n                this.setState({\n                    valid:\n                        this.state.name &&\n                        this.state.email &&\n                        this.state.address\n                });\n            }\n        );\n    }\n\n    check_coupon() {\n        clearInterval(this.check_coupon_timer);\n\n        this.check_coupon_timer = setTimeout(async () => {\n            let res = await axios.get(\n                '/stickers/check_code/' + this.state.coupon\n            );\n\n            let valid = res.data.valid;\n\n            if (valid) {\n                this.setState({\n                    discounted: valid,\n                    quantity: 2\n                });\n            }\n        }, 300);\n    }\n\n    submit(e) {\n        return axios\n            .post('/stickers/order', {\n                tx: null,\n                quantity: this.state.quantity,\n                name: this.state.name,\n                email: this.state.email,\n                address: this.state.address,\n                coupon: this.state.valid ? this.state.coupon : null\n            })\n            .then((res) => {\n                if (res.status >= 300) {\n                    return bootbox.alert(\n                        'There was a problem submitting your order'\n                    );\n                }\n\n                return bootbox.alert(\n                    'Your order was placed successfully, thanks. Please ' +\n                        'reference Order ID #' +\n                        res.data.order_id +\n                        ' if necessary.',\n                    () => {\n                        location = location;\n                    }\n                );\n            });\n    }\n\n    render() {\n        return (\n            <>\n                <h4 class=\"f300\">Engineer Man Stickers 2\" x 2\"</h4>\n\n                <img src=\"/images/sticker_2019.png\" class=\"sticker\" />\n\n                <p>\n                    Stickers are made with vinyl making them weatherproof and\n                    resistant to scratching and fading. Stickers cannot be\n                    removed and reapplied.\n                </p>\n\n                <form>\n                    <div class=\"form-group\">\n                        <label class=\"f700\">Quantity</label>\n                        <br />\n                        {(this.state.discounted && (\n                            <div class=\"quantity_option active\">2 for FREE</div>\n                        )) ||\n                            this.props.options\n                                .filter((option) => option.cost !== 'FREE')\n                                .map((option) => {\n                                    return (\n                                        <>\n                                            <div\n                                                class={\n                                                    'quantity_option ' +\n                                                    (this.state.quantity ===\n                                                        option.quantity &&\n                                                        'active')\n                                                }\n                                                onClick={() =>\n                                                    this.setState({\n                                                        quantity:\n                                                            option.quantity\n                                                    })\n                                                }\n                                            >\n                                                {option.quantity} for $\n                                                {option.cost}\n                                            </div>{' '}\n                                        </>\n                                    );\n                                })}\n                    </div>\n                    <div class=\"form-group\">\n                        <label class=\"f700\">Name</label>\n                        <input\n                            type=\"text\"\n                            id=\"name\"\n                            name=\"name\"\n                            class=\"form-control\"\n                            placeholder=\"Enter your name here\"\n                            autocomplete=\"off\"\n                            onChange={this.handle_update}\n                        />\n                    </div>\n\n                    <div class=\"form-group\">\n                        <label class=\"f700\">Email</label>\n                        <input\n                            type=\"text\"\n                            id=\"email\"\n                            name=\"email\"\n                            class=\"form-control\"\n                            placeholder=\"Enter your email here\"\n                            autocomplete=\"off\"\n                            onChange={this.handle_update}\n                        />\n                    </div>\n\n                    <div class=\"form-group\">\n                        <label class=\"f700\">\n                            Address (anywhere in the world)\n                        </label>\n                        <textarea\n                            type=\"text\"\n                            id=\"address\"\n                            name=\"address\"\n                            class=\"form-control\"\n                            placeholder=\"Please enter exactly what should appear on an envelope\"\n                            autocomplete=\"off\"\n                            rows=\"5\"\n                            onChange={this.handle_update}\n                        ></textarea>\n                    </div>\n\n                    <div class=\"form-group\">\n                        <label class=\"f700\">Coupon</label>\n                        <input\n                            type=\"text\"\n                            id=\"coupon\"\n                            name=\"coupon\"\n                            class=\"form-control\"\n                            placeholder=\"If you have a coupon, enter it here\"\n                            autocomplete=\"off\"\n                            disabled={this.state.discounted}\n                            onChange={this.handle_update}\n                        />\n                        {this.state.coupon && this.state.discounted && (\n                            <small class=\"text-success\">Coupon valid</small>\n                        )}\n                    </div>\n                </form>\n                {(this.state.discounted && (\n                    <button\n                        type=\"button\"\n                        class=\"btn btn-success\"\n                        disabled={!this.state.valid}\n                        onClick={this.submit}\n                    >\n                        Submit\n                    </button>\n                )) || (\n                    <div\n                        id=\"paypal-button\"\n                        style={{\n                            visibility:\n                                !this.state.discounted && this.state.valid\n                                    ? 'visible'\n                                    : 'hidden'\n                        }}\n                    ></div>\n                )}\n            </>\n        );\n    }\n}\n\nUtil.try_render('react_stickers', Stickers);\n\nexport default Stickers;\n"
  },
  {
    "path": "platform/resources/jsx/users.jsx",
    "content": "import React from 'react';\nimport axios from 'axios';\nimport moment from 'moment';\n\nimport Util from 'js/util';\n\nclass Users extends React.Component {\n    constructor(props) {\n        super(props);\n\n        this.state = {\n            users: props.users\n        };\n    }\n\n    search = (e) => {\n        let users = this.props.users.filter((user) =>\n            user.display_name\n                .toLowerCase()\n                .includes(e.target.value.toLowerCase())\n        );\n\n        this.setState({\n            users\n        });\n    };\n\n    render() {\n        return (\n            <div>\n                <input\n                    class=\"form-control\"\n                    type=\"text\"\n                    placeholder=\"Search\"\n                    onChange={this.search}\n                />\n                <table class=\"table table-sm table-dark\">\n                    <tr>\n                        <th style={{ width: '100px' }}></th>\n                        <th style={{ width: '100px' }}>User ID</th>\n                        <th>Username</th>\n                        <th>Display Name</th>\n                        <th>Registered</th>\n                    </tr>\n                    {this.state.users.map((user) => {\n                        return (\n                            <tr>\n                                <td>\n                                    <a\n                                        key={user.user_id}\n                                        href={\n                                            '/admin/users/login_as?user_id=' +\n                                            user.user_id\n                                        }\n                                        class=\"user_row marginbottom20\"\n                                    >\n                                        Login As\n                                    </a>\n                                </td>\n                                <td>{user.user_id}</td>\n                                <td>{user.username}</td>\n                                <td>{user.display_name}</td>\n                                <td>\n                                    {moment(user.created_at).format(\n                                        'MMMM Do, YYYY'\n                                    )}\n                                </td>\n                            </tr>\n                        );\n                    })}\n                </table>\n            </div>\n        );\n    }\n}\n\nUtil.try_render('react_users', Users);\n\nexport default Users;\n"
  },
  {
    "path": "platform/resources/less/bootstrap.less",
    "content": ".btn-success {\n    background-color: #37b86e;\n    &:hover {\n        background-color: #289254;\n    }\n}\n\n.badge-success {\n    background-color: #37b86e;\n}\n\n.dropdown-menu {\n    a:visited,\n    a:link,\n    a:hover {\n        color: #333 !important;\n    }\n    a:active {\n        color: #fff !important;\n    }\n    .dropdown-item {\n        &:active {\n            background-color: #36b96e;\n        }\n    }\n}\n\n.bootbox-body {\n    text-align: left;\n    color: #000;\n}\n\n.highlightjs * {\n    font-size: 14px !important;\n    font-family: monospace !important;\n}\n\nselect {\n    background: none !important;\n    outline: none !important;\n    border: #999 1px solid !important;\n    background: #282c34 !important;\n    color: #fff !important;\n}\n\ninput.form-control,\ntextarea.form-control {\n    background: none !important;\n    border: 0 !important;\n    border-bottom: #666 1px solid !important;\n    padding-left: 0 !important;\n    outline: 0 !important;\n    color: #fff !important;\n    &:focus {\n        box-shadow: none !important;\n        outline: 0 !important;\n    }\n}\n\n.form-box {\n    padding: 15px;\n    background: #21252b;\n    margin: 30px 0;\n}\n\nhr {\n    border-top: #000 1px solid;\n}\n\n.btn {\n    &:focus {\n        box-shadow: none;\n    }\n}\n\ntable {\n    th {\n        border-top: 0 !important;\n    }\n}\n\n.text-warning {\n    color: #ffdd78 !important;\n}\n"
  },
  {
    "path": "platform/resources/less/colors.less",
    "content": "@challenge_easy: #84e47f;\n@challenge_medium: #e4e37f;\n@challenge_hard: #e47f8d;\n\n.green {\n    color: #8aecb4;\n}\n"
  },
  {
    "path": "platform/resources/less/em/challenge.less",
    "content": "@import '../colors.less';\n\n.em_challenge {\n    position: absolute;\n    top: 56px;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    display: flex;\n\n    pre {\n        font: inherit;\n        color: inherit;\n        display: inline;\n    }\n\n    .instructions {\n        width: 360px;\n        overflow-y: auto;\n        padding: 15px;\n    }\n\n    .editor {\n        flex: 1;\n        position: relative;\n    }\n\n    #editor {\n        position: absolute;\n        top: 0;\n        left: 0;\n        right: 0;\n        bottom: 0;\n    }\n\n    .easy {\n        color: @challenge_easy;\n    }\n\n    .medium {\n        color: @challenge_medium;\n    }\n\n    .hard {\n        color: @challenge_hard;\n    }\n\n    .results {\n        position: fixed;\n        top: 70%;\n        bottom: 0;\n        left: 454px;\n        right: 30px;\n        background: rgba(0, 0, 0, 0.3);\n        padding: 25px;\n        overflow: auto;\n        .result {\n            background: rgba(0, 0, 0, 0.2);\n            padding: 10px 15px;\n            margin-bottom: 10px;\n            color: #fff;\n            font-family: SFMono-Regular, Menlo, Monaco, Consolas,\n                'Liberation Mono', 'Courier New', monospace;\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/challenge_abstract.less",
    "content": ".em_challenge .abstract,\n#react_manage_challenge .ql-editor {\n    .input {\n        p:last-child {\n            margin-bottom: 0;\n        }\n    }\n    .wrap {\n        word-break: break-all;\n    }\n\n    .test_case {\n        background: rgba(0, 0, 0, 0.2);\n        padding: 10px 15px;\n        margin-bottom: 10px;\n        color: #fff;\n        font-family: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',\n            'Courier New', monospace;\n        > * {\n            margin-bottom: 5px;\n        }\n    }\n\n    p {\n        margin: 0;\n        padding: 0;\n    }\n\n    h4 {\n        font-weight: 300;\n    }\n\n    .value-badge {\n        color: #fff;\n        background-color: #007bff;\n        display: inline-block;\n        padding: 0.25em 0.4em;\n        font-size: 75%;\n        font-weight: 700;\n        line-height: 1;\n        text-align: center;\n        white-space: nowrap;\n        vertical-align: baseline;\n        border-radius: 0.25rem;\n        transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out,\n            border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n    }\n\n    pre {\n        display: block;\n        font-size: 87.5%;\n        color: #212529;\n    }\n\n    .section {\n        margin-bottom: 30px;\n    }\n\n    .input {\n        background: rgba(0, 0, 0, 0.2);\n        padding: 10px 15px;\n        margin-bottom: 10px;\n        color: #fff;\n    }\n\n    .ql-syntax {\n        background: rgba(0, 0, 0, 0.2);\n        padding: 10px 15px;\n        margin-bottom: 20px;\n        margin-top: -5px;\n        color: #fff;\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/challenge_manage.less",
    "content": ".em_challenge_manage {\n    .case_box {\n        padding: 15px;\n        background: #1b1f27;\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/challenges_list.less",
    "content": "@import '../colors.less';\n\n.em_challenges_list {\n    .challenge_list {\n        margin-bottom: 20px;\n        .challenge {\n            display: block;\n            background: #21252b;\n            padding: 10px;\n            margin-bottom: 8px;\n            color: #fff;\n            .title {\n                font-size: 18px;\n            }\n            .description {\n                font-weight: 300;\n            }\n            &:hover {\n                background: #2f353e;\n            }\n        }\n    }\n    .easy {\n        .title {\n            .badge {\n                float: right;\n            }\n            .text {\n                color: @challenge_easy;\n            }\n        }\n    }\n    .medium {\n        .title {\n            .badge {\n                float: right;\n            }\n            .text {\n                color: @challenge_medium;\n            }\n        }\n    }\n    .hard {\n        .title {\n            .badge {\n                float: right;\n            }\n            .text {\n                color: @challenge_hard;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/common_content.less",
    "content": ".em_common_content {\n    max-width: 1140px;\n    width: 100%;\n    margin-left: auto;\n    margin-right: auto;\n    padding: 40px 15px;\n    h4 {\n        margin-bottom: 10px;\n    }\n    .version {\n        margin-top: -5px;\n    }\n    .col-4 {\n        margin-top: 5px;\n    }\n}\n\n.em_wide_content {\n    padding: 20px 15px;\n    h4 {\n        margin-bottom: 10px;\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/community_map.less",
    "content": ".em_community_map {\n    max-width: 1100px;\n    width: 100%;\n    margin: auto;\n    padding: 30px 15px;\n    .link_list {\n        background: #000;\n        background: #21252b;\n        padding: 10px;\n        margin-bottom: 20px;\n        a {\n            display: block;\n            margin-bottom: 6px;\n            &:last-child {\n                margin-bottom: 0;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/container.less",
    "content": ".em_container {\n    display: inline-block;\n    margin: auto;\n    /*max-width: 1440px;*/\n    width: 100%;\n    text-align: left;\n    background: #282c34;\n    min-height: 100vh;\n}\n"
  },
  {
    "path": "platform/resources/less/em/contests/contest.less",
    "content": ".em_contests_contest {\n    .ql-editor {\n        padding-left: 0;\n        padding-right: 0;\n    }\n    .header {\n        margin-bottom: 0;\n    }\n    .description {\n        padding: 30px 0;\n    }\n    .case_text {\n        color: #fff;\n        background: #24282f;\n        padding: 8px;\n    }\n    .submission {\n        padding: 10px;\n        background: rgba(0, 0, 0, 0.1);\n        margin-bottom: 10px;\n        .heading {\n            display: flex;\n            .main {\n                flex: 1;\n            }\n            .summary {\n                img {\n                    width: auto;\n                    height: 28px;\n                    margin-left: 6px;\n                }\n            }\n            .user {\n                padding-top: 8px;\n                color: #fff;\n                img {\n                    width: 28px;\n                    height: 28px;\n                }\n            }\n            .time {\n                font-size: 12px;\n                color: #aaa;\n            }\n            .explanation_text {\n                font-size: 12px;\n            }\n        }\n        .solution {\n            margin-left: -8px;\n            margin-right: -8px;\n            margin-top: 5px;\n            padding: 10px;\n            font-size: 12px;\n            font-family: monospace;\n            word-wrap: break-word;\n            color: #fff;\n            background: rgba(0, 0, 0, 0.1);\n            margin-bottom: 0;\n            white-space: pre-wrap;\n        }\n    }\n    .tab-active {\n        background-color: #3771b8;\n    }\n    .space-between {\n        display: flex;\n        justify-content: space-between;\n        align-items: center;\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/contests/home.less",
    "content": ".em_contests_home {\n    * {\n        color: #fff;\n    }\n    .active {\n        margin-bottom: 40px;\n    }\n    .past {\n        margin-bottom: 40px;\n    }\n    .contest {\n        display: block;\n        background: rgba(0, 0, 0, 0.3);\n        padding: 15px;\n        margin-bottom: 20px;\n        .name {\n            font-size: 22px;\n            margin-bottom: 10px;\n        }\n        .time_left {\n            background: rgba(67, 103, 82, 0.5);\n            padding: 8px 12px;\n            margin-bottom: 6px;\n        }\n        .solutions {\n            background: rgb(37, 42, 49);\n            padding: 8px 12px;\n            font-size: 20px;\n            font-weight: 700;\n            margin-top: 14px;\n            img {\n                width: 32px;\n                height: 32px;\n                margin-bottom: 4px;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/contests/manage.less",
    "content": ".em_contest_manage {\n    .wrapper {\n        display: flex;\n\n        .left {\n            flex: 1;\n            padding-right: 15px;\n        }\n\n        .right {\n            width: 300px;\n        }\n    }\n\n    .control_button {\n        margin-top: 10px;\n        width: 150px;\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/footer.less",
    "content": ".em_footer {\n    position: absolute;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    background: #36b96e;\n    font-size: 12px;\n    padding: 0 10px;\n    text-align: right;\n    a {\n        color: #fff;\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/language_choice.less",
    "content": "@import '../colors.less';\n\n.em_language_choice {\n    .icons > div {\n        text-align: center;\n        margin-bottom: 30px;\n    }\n    h4 {\n        margin: 15px 0;\n    }\n    .easy {\n        color: @challenge_easy;\n    }\n    .medium {\n        color: @challenge_medium;\n    }\n    .hard {\n        color: @challenge_hard;\n    }\n}\n\n.badge-easy {\n    background-color: @challenge_easy;\n}\n.badge-medium {\n    background-color: @challenge_medium;\n}\n.badge-hard {\n    background-color: @challenge_hard;\n}\n"
  },
  {
    "path": "platform/resources/less/em/login.less",
    "content": ".em_login {\n    display: none;\n    &.open {\n        display: block;\n    }\n    .backdrop {\n        position: absolute;\n        top: 0;\n        left: 0;\n        bottom: 0;\n        right: 0;\n        background: rgba(0, 0, 0, 0.2);\n        text-align: center;\n        z-index: 10;\n    }\n    .close {\n        position: absolute;\n        top: 8px;\n        right: 8px;\n        cursor: pointer;\n        i {\n            color: #fff;\n            &:hover {\n                color: #eee;\n            }\n        }\n    }\n    .box {\n        display: inline-block;\n        position: relative;\n        max-width: 450px;\n        width: 100%;\n        margin-top: 30px;\n        background: #222;\n        padding: 30px;\n        p {\n            color: #aaa;\n            margin-top: 20px;\n            margin-bottom: 25px;\n        }\n        a {\n            color: #fff;\n            background: #7289da;\n            &:hover {\n                background: #687bc0;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/manage_snippet.less",
    "content": ".em_manage_snippet {\n    #editor {\n        height: calc(100vh - 144px);\n        @media (max-width: 700px) {\n            height: calc(100vh - 190px);\n        }\n    }\n    .menu {\n        .wrapper {\n            display: flex;\n            background: #21252b;\n            align-items: center;\n            padding: 10px 10px 10px 75px;\n            @media (max-width: 700px) {\n                display: grid;\n                grid-template-columns: 1fr;\n                align-items: unset;\n                place-items: center;\n                gap: 0.5rem;\n            }\n            > * {\n                display: inline-block;\n                vertical-align: middle;\n            }\n            .language {\n                flex: 1;\n                select {\n                    width: 200px;\n                }\n            }\n            .language_label {\n                margin-right: 10px;\n                flex: 1;\n            }\n            .control-button {\n                margin-right: 0.5rem;\n            }\n        }\n    }\n    .run-data {\n        display: flex;\n        width: 100%;\n        overflow: auto;\n        pre {\n            font: unset;\n            color: unset;\n        }\n        .inputs-outputs {\n            width: 100%;\n            padding: 20px 15px;\n        }\n    }\n    .info {\n        background-color: rgba(0, 0, 0, 0.3);\n        min-height: 20px;\n        margin-bottom: 10px;\n        padding: 10px 5px 5px 5px;\n        overflow-x: auto;\n        max-width: 600px;\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/menu.less",
    "content": ".em_menu {\n    display: flex;\n    padding: 10px;\n    background: #36b96e;\n    .mobile_expand {\n        display: none;\n        i {\n            color: #fff;\n            font-size: 20px;\n            margin: 8px;\n            cursor: pointer;\n            margin-right: 14px;\n        }\n        @media (max-width: 700px) {\n            display: inline;\n        }\n    }\n    .brand_icon {\n        display: inline;\n        img {\n            height: 36px;\n            width: auto;\n        }\n        img:hover {\n            opacity: 70%;\n        }\n    }\n    .main_links {\n        display: inline-block;\n        > * {\n            display: inline-block;\n            vertical-align: middle;\n        }\n        > a {\n            background: rgb(18, 101, 54);\n            color: #fff !important;\n            margin-left: 10px;\n            border-radius: 5px;\n            cursor: pointer;\n            padding: 6px 10px;\n            &:hover {\n                background: #349a60 !important;\n            }\n        }\n        > .dropdown {\n            background: rgb(18, 101, 54);\n            color: #fff !important;\n            margin-left: 10px;\n            border-radius: 5px;\n            cursor: pointer;\n            > a {\n                color: #fff !important;\n                padding: 5px 10px;\n                display: inline-block;\n            }\n            &:hover {\n                background: #349a60;\n            }\n        }\n        @media (max-width: 700px) {\n            display: none;\n        }\n    }\n    .search {\n        flex: 1;\n        margin-left: 10px;\n        margin-right: 10px;\n        input {\n            width: 100%;\n            border: none;\n            background: #4aa571;\n            outline: none;\n            color: #fff;\n            padding: 6px 10px;\n            border-radius: 5px;\n            &::-webkit-input-placeholder {\n                color: #fff;\n            }\n            &:-moz-placeholder {\n                color: #fff;\n                opacity: 1;\n            }\n            &::-moz-placeholder {\n                color: #fff;\n                opacity: 1;\n            }\n            &:-ms-input-placeholder {\n                color: #fff;\n            }\n            &::-ms-input-placeholder {\n                color: #fff;\n            }\n            &::placeholder {\n                color: #fff;\n            }\n        }\n    }\n    .user_meta {\n        * {\n            vertical-align: middle;\n        }\n        img {\n            border-radius: 50%;\n            height: 36px;\n            width: auto;\n            margin-left: 10px;\n        }\n        .dropdown {\n            display: inline-block;\n            cursor: pointer;\n        }\n        i {\n            margin-right: 3px;\n        }\n        @media (max-width: 700px) {\n            display: none;\n        }\n    }\n    .login {\n        > a {\n            display: inline-block;\n            vertical-align: middle;\n            background: #1987b1;\n            color: #fff !important;\n            border-radius: 5px;\n            cursor: pointer;\n            padding: 6px 10px;\n            &:hover {\n                background: #37a7d2 !important;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/mobile_nav.less",
    "content": ".em_mobile_nav {\n    display: none;\n    &.open {\n        display: inline;\n    }\n    .backdrop {\n        position: absolute;\n        top: 0;\n        left: 0;\n        bottom: 0;\n        right: 0;\n        background: rgba(0, 0, 0, 0.6);\n        text-align: center;\n    }\n    .close {\n        position: absolute;\n        top: 8px;\n        right: 8px;\n        cursor: pointer;\n        i {\n            color: #fff;\n            &:hover {\n                color: #eee;\n            }\n        }\n    }\n    .menu {\n        position: absolute;\n        top: 0;\n        left: 0;\n        bottom: 0;\n        width: 75%;\n        background: #282c34;\n        color: #fff;\n        text-align: left;\n        z-index: 1;\n        .contents {\n            padding: 16px;\n            a {\n                display: block;\n                padding: 10px;\n                background: #22262c;\n                margin-bottom: 4px;\n            }\n            .spacer {\n                height: 20px;\n            }\n        }\n    }\n    @media (min-width: 701px) {\n        display: none !important;\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/power_system.less",
    "content": ".em_power_system {\n    .tier_circle {\n        border-radius: 50%;\n        width: 100%;\n        padding-top: 100%;\n        position: relative;\n        margin-bottom: 30px;\n        .wrapper {\n            position: absolute;\n            top: ~'calc(50% - 30px)';\n            left: 0;\n            right: 0;\n            text-align: center;\n            .tier {\n                font-size: 26px;\n                font-weight: 700;\n            }\n            .score {\n                font-size: 26px;\n                font-weight: 300;\n            }\n        }\n    }\n    .novice {\n        background: #79acbf;\n    }\n    .hero {\n        background: #7d9dc5;\n    }\n    .master {\n        background: #acb2e4;\n    }\n    .legend {\n        background: #d2ace4;\n    }\n    .power_list {\n        .item {\n            display: flex;\n            background: #21252b;\n            margin-bottom: 4px;\n            padding: 6px 12px;\n            font-size: 18px;\n            div {\n                flex: 1;\n                color: #8fdcef;\n            }\n            span {\n                width: 80px;\n                padding-left: 30px;\n                font-weight: 700;\n            }\n        }\n        .heading:first-child {\n            margin-top: 0;\n        }\n        .heading {\n            margin-top: 30px;\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/profile.less",
    "content": "@import '../colors.less';\n\n.em_profile {\n    .content {\n        display: flex;\n        .left {\n            width: 220px;\n            .padding {\n                padding: 0 10px;\n            }\n        }\n        .right {\n            flex: 1;\n        }\n    }\n    .avatar {\n        width: 100%;\n        height: auto;\n        margin-bottom: 10px;\n    }\n    .awards {\n        margin-bottom: 30px;\n        .award {\n            display: inline-block;\n            text-align: center;\n            margin: 5px 10px 10px 10px;\n            img {\n                margin-bottom: 5px;\n                cursor: pointer;\n            }\n        }\n        .count {\n            background: rgba(0, 0, 0, 0.4);\n            color: #fff;\n            text-align: center;\n            display: inline-block;\n            border-radius: 20px;\n            padding: 2px 10px;\n        }\n    }\n    .challenge {\n        display: block;\n        background: rgba(0, 0, 0, 0.3);\n        padding: 10px;\n        margin-bottom: 10px;\n        a {\n            color: #fff;\n        }\n        &.easy {\n            border-left: @challenge_easy 5px solid;\n        }\n        &.medium {\n            border-left: @challenge_medium 5px solid;\n        }\n        &.hard {\n            border-left: @challenge_hard 5px solid;\n        }\n        p {\n            margin-bottom: 8px;\n        }\n    }\n    .view_solution {\n        width: 80px;\n        height: 48px;\n        background: #126536;\n        padding-right: 10px;\n        padding-left: 10px;\n        margin-bottom: 10px;\n        & p {\n            margin-bottom: 0;\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/staff_container.less",
    "content": ".em_staff_container {\n    padding: 4px 10px;\n    background: #313847;\n}\n"
  },
  {
    "path": "platform/resources/less/em/stickers.less",
    "content": ".em_stickers {\n    .sticker {\n        max-width: 200px;\n        width: 100%;\n        height: auto;\n        margin-top: 20px;\n        margin-bottom: 20px;\n    }\n    .quantity_option {\n        display: inline-block;\n        padding: 10px 18px;\n        border: #555 1px solid;\n        &.active {\n            background: #208a4d;\n        }\n        &:hover {\n            cursor: pointer;\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/em/top_members.less",
    "content": ".em_top_members {\n    .user_row {\n        position: relative;\n        display: flex;\n        margin-bottom: 4px;\n        background: #202329;\n        .score_progress {\n            position: absolute;\n            left: 0;\n            top: 85%;\n            bottom: 0;\n        }\n        .picture {\n            z-index: 1;\n            img {\n                width: 40px;\n                height: 40px;\n            }\n        }\n        .name {\n            z-index: 1;\n            flex: 1;\n            .wrapper {\n                display: inline-block;\n                padding: 2px 8px;\n                border-radius: 20px;\n                text-align: center;\n                margin-top: 6px;\n                margin-left: 6px;\n                color: #fff;\n            }\n        }\n        .power {\n            z-index: 1;\n            width: 100px;\n            text-align: right;\n            .wrapper {\n                display: inline-block;\n                padding: 2px 8px;\n                border-radius: 20px;\n                text-align: center;\n                margin-top: 6px;\n                margin-right: 6px;\n                color: #fff;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/less/global.less",
    "content": "html,\nbody {\n    font-family: 'Lato', sans-serif;\n    color: #fff;\n}\n\nbody {\n    text-align: center;\n    background: #282c34;\n}\n\na {\n    color: #68e69e;\n    &:visited,\n    &:active {\n        color: #68e69e;\n    }\n    &:hover {\n        color: #32a965;\n        text-decoration: none;\n    }\n}\n\ntable {\n    .actions {\n        a {\n            margin-right: 10px;\n        }\n    }\n}\n\n.pointer {\n    cursor: pointer;\n}\n\n.accent_text {\n    font-style: italic;\n    color: #8aecb4;\n}\n\n.center {\n    text-align: center;\n}\n\n.f100 {\n    font-weight: 100;\n}\n\n.f300 {\n    font-weight: 300;\n}\n\n.f400 {\n    font-weight: 400;\n}\n\n.f700 {\n    font-weight: 700;\n}\n\n.f900 {\n    font-weight: 900;\n}\n\n.margin0 {\n    margin: 0 !important;\n}\n\n.margintop5 {\n    margin-top: 5px !important;\n}\n\n.margintop10 {\n    margin-top: 10px !important;\n}\n\n.margintop15 {\n    margin-top: 15px !important;\n}\n\n.margintop20 {\n    margin-top: 20px !important;\n}\n\n.margintop25 {\n    margin-top: 25px !important;\n}\n\n.margintop30 {\n    margin-top: 30px !important;\n}\n\n.margintop40 {\n    margin-top: 40px !important;\n}\n\n.margintop50 {\n    margin-top: 50px !important;\n}\n\n.margintop60 {\n    margin-top: 60px !important;\n}\n\n.margintop70 {\n    margin-top: 70px !important;\n}\n\n.margintop80 {\n    margin-top: 80px !important;\n}\n\n.margintop90 {\n    margin-top: 90px !important;\n}\n\n.margintop100 {\n    margin-top: 100px !important;\n}\n\n.marginbottom0 {\n    margin-bottom: 0 !important;\n}\n\n.marginbottom5 {\n    margin-bottom: 5px !important;\n}\n\n.marginbottom10 {\n    margin-bottom: 10px !important;\n}\n\n.marginbottom20 {\n    margin-bottom: 20px !important;\n}\n\n.marginbottom30 {\n    margin-bottom: 30px !important;\n}\n\n.marginbottom40 {\n    margin-bottom: 40px !important;\n}\n\n.marginbottom50 {\n    margin-bottom: 50px !important;\n}\n\n.marginbottom60 {\n    margin-bottom: 60px !important;\n}\n\n.marginbottom70 {\n    margin-bottom: 70px !important;\n}\n\n.marginbottom80 {\n    margin-bottom: 80px !important;\n}\n\n.marginbottom90 {\n    margin-bottom: 90px !important;\n}\n\n.marginbottom100 {\n    margin-bottom: 100px !important;\n}\n\n.width-60 {\n    width: 60px;\n}\n\n.width-80 {\n    width: 80px;\n}\n\n::selection {\n    color: white;\n    background: #32a965;\n}\n"
  },
  {
    "path": "platform/resources/less/highlightjs.less",
    "content": "td.hljs-ln-code {\n    padding-left: 10px !important;\n}\ntd.hljs-ln-numbers {\n    background: #1b1f27;\n    padding-left: 5px !important;\n    padding-right: 15px !important;\n}\n"
  },
  {
    "path": "platform/resources/less/quill.less",
    "content": ".ql-toolbar {\n    background: #1b1f27 !important;\n    border: 0 !important;\n    svg {\n        * {\n            stroke: #fff !important;\n        }\n    }\n    .ql-strike,\n    .ql-header {\n        svg * {\n            fill: #fff !important;\n        }\n    }\n    .ql-picker-label {\n        &:hover {\n            color: #fff !important;\n        }\n    }\n    button {\n        &:hover {\n            background: #4aa571 !important;\n        }\n    }\n}\n\n.ql-container {\n    border: 0 !important;\n    border-bottom: #7b7b7b 1px solid !important;\n    font-size: 14px !important;\n    background: #1b1f27 !important;\n    font-family: Lato, sans-serif;\n}\n\n.ql-blank {\n    &:before {\n        color: #ddd !important;\n        font-style: normal !important;\n    }\n}\n\n.ql-editor {\n    font-size: 16px;\n    min-height: 200px;\n    .ql-syntax {\n        margin-top: 10px;\n        * {\n            font-family: monospace !important;\n        }\n    }\n}\n"
  },
  {
    "path": "platform/resources/main.js",
    "content": "import 'core-js/stable';\nimport 'regenerator-runtime/runtime';\n\nimport axios from 'axios';\n\ntry {\n    axios.defaults.validateStatus = () => true;\n} catch (e) {}\n\n((ctx) => {\n    return ctx.keys().map(ctx);\n})(require.context('./js', true, /\\.js$/));\n\n((ctx) => {\n    return ctx.keys().map(ctx);\n})(require.context('./jsx', true, /\\.jsx$/));\n\n((ctx) => {\n    return ctx.keys().map(ctx);\n})(require.context('./less', true, /\\.less$/));\n"
  },
  {
    "path": "platform/resources/monaco.js",
    "content": "import * as monaco from 'monaco-editor';\n\nmonaco.editor.defineTheme('em', {\n    base: 'vs-dark',\n    inherit: true,\n    rules: [{ background: '282C34' }],\n    colors: {\n        'editorGutter.background': '#21252B',\n        'editor.background': '#282C34',\n        'scrollbarSlider.background': '#21252B',\n        'scrollbarSlider.hoverBackground': '#21252B',\n        'scrollbarSlider.activeBackground': '#21252B'\n    }\n});\n\nwindow.monaco = monaco;\n"
  },
  {
    "path": "platform/resources/twig/filters.js",
    "content": "const contains = (array, value) => {\n    if (value === undefined || value === null) {\n        return false;\n    }\n\n    for (let checking of array) {\n        let found = true;\n\n        for (let entry of Object.entries(checking)) {\n            if (value[0][entry[0]] !== entry[1]) {\n                found = false;\n            }\n        }\n\n        if (found) {\n            return true;\n        }\n    }\n\n    return false;\n};\n\nmodule.exports = [\n    {\n        name: 'contains',\n        filter: contains\n    }\n];\n"
  },
  {
    "path": "platform/start",
    "content": "#!/usr/bin/env bash\n\nAPPENV=${APPENV:-development}\n\necho \"running in $APPENV mode\"\n\nif [ $APPENV == \"production\" ]; then\n    npm run prod\nelse\n    npm run dev\nfi\n"
  },
  {
    "path": "platform/views/_emails/new_user.twig",
    "content": "{% extends '_emails/container.twig' %}\n{% block content %}\n\n{% endblock %}\n"
  },
  {
    "path": "platform/views/admin/challenges/update.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <div class=\"em_wide_content\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <div\n                    id=\"react_manage_challenge\"\n                    data-mode=\"{{ mode|json_encode|e }}\"\n                    data-challenge=\"{{ challenge|json_encode|e }}\"\n                ></div>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/admin/challenges/view_all.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <div class=\"em_wide_content\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">\n                    Challenges\n                    <small>\n                        <a href=\"/admin/challenges/create\">\n                            <i class=\"fa fa-plus\"></i>\n                        </a>\n                    </small>\n                </h4>\n\n                <table class=\"table table-striped table-sm\">\n                    <thead>\n                        <tr>\n                            <th style=\"width: 90px;\"></th>\n                            <th style=\"width: 90px;\">ID</th>\n                            <th style=\"width: 120px;\">Difficulty</th>\n                            <th>Name</th>\n                        </tr>\n                    </thead>\n                    <tbody>\n                        {% for challenge in challenges %}\n                            <tr>\n                                <td class=\"actions center\">\n                                    <a href=\"/admin/challenges/update/{{ challenge.challenge_id }}\">\n                                        <i class=\"fa fa-pencil-alt\"></i>\n                                    </a>\n                                    <a href=\"/challenges/choose_language/{{ challenge.challenge_id }}\">\n                                        <i class=\"fa fa-search\"></i>\n                                    </a>\n                                </td>\n                                <td>{{ challenge.challenge_id }}</td>\n                                <td>{{ challenge.difficulty_name }}</td>\n                                <td>{{ challenge.name }}</td>\n                            </tr>\n                        {% endfor %}\n                    </tbody>\n                </table>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/admin/contests/update.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <div class=\"em_wide_content\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">Manage Contest</h4>\n\n                <div\n                    id=\"react_contest_manage\"\n                    data-mode=\"{{ mode|json_encode|e }}\"\n                    data-contest_id=\"{{ contest.contest_id|json_encode|e }}\"\n                    data-contest=\"{{ contest|json_encode|e }}\"\n                    data-languages=\"{{ req.local.constant.contests|json_encode|e }}\"\n                ></div>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/admin/contests/view_all.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <div class=\"em_wide_content\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">\n                    Contests\n                    <small>\n                        <a href=\"/admin/contests/create\">\n                            <i class=\"fa fa-plus\"></i>\n                        </a>\n                    </small>\n                </h4>\n\n                <table class=\"table table-striped table-sm\">\n                    <thead>\n                        <tr>\n                            <th style=\"width: 90px;\"></th>\n                            <th style=\"width: 60px;\">ID</th>\n                            <th>Name</th>\n                            <th style=\"width: 140px;\">Start</th>\n                            <th style=\"width: 140px;\">End</th>\n                        </tr>\n                    </thead>\n                    <tbody>\n                        {% for contest in contests %}\n                            <tr>\n                                <td class=\"actions center\">\n                                    <a href=\"/admin/contests/update/{{ contest.contest_id }}\">\n                                        <i class=\"fa fa-pencil-alt\"></i>\n                                    </a>\n                                    <a href=\"{{ contest.url }}\">\n                                        <i class=\"fa fa-search\"></i>\n                                    </a>\n                                </td>\n                                <td>{{ contest.contest_id }}</td>\n                                <td>{{ contest.name }}</td>\n                                <td>{{ contest.start_date|date('m/d/Y') }}</td>\n                                <td>{{ contest.end_date|date('m/d/Y') }}</td>\n                            </tr>\n                        {% endfor %}\n                    </tbody>\n                </table>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/admin/dashboard/dashboard.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <div class=\"em_wide_content\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">Dashboard</h4>\n                Nothing here, choose from above.\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/admin/piston/view_all.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}Piston | EMKC{% endblock %}\n{% block content %}\n    <div\n        id=\"react_ppman\"\n        data-message=\"{{ message|json_encode|e }}\"\n    ></div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/admin/users/view_all.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}Users | EMKC{% endblock %}\n{% block content %}\n    <div\n        id=\"react_users\"\n        data-users=\"{{ users|json_encode|e }}\"\n    ></div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/challenges/challenge.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}{{ challenge.difficulty_name_upper }} Challenge: {{ challenge.name }} | EMKC{% endblock %}\n{% block css %}\n    {{ parent() }}\n    <style>\n        body {\n            overflow: hidden;\n        }\n    </style>\n{% endblock %}\n{% block bundles %}\n    <script src=\"/lib/webpack/monaco.bundle.js?{{ sails.local.epoch }}\"></script>\n{% endblock %}\n{% block content %}\n    <div\n        id=\"react_challenge\"\n        data-solved=\"{{ solved|json_encode|e }}\",\n        data-challenge=\"{{ challenge|json_encode|e }}\",\n        data-language=\"{{ language|json_encode|e }}\",\n        data-monaco_language=\"{{ monaco_language|json_encode|e }}\",\n        data-abstract=\"{{ abstract|json_encode|e }}\",\n        data-template=\"{{ template|json_encode|e }}\"\n    ></div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/challenges/choose_language.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}Coding Challenges | EMKC{% endblock %}\n{% block content %}\n    {% if challenge.difficulty == sails.local.constant.challenges.difficulty.easy %}\n        {% set diff = 'easy' %}\n    {% endif %}\n    {% if challenge.difficulty == sails.local.constant.challenges.difficulty.medium %}\n        {% set diff = 'medium' %}\n    {% endif %}\n    {% if challenge.difficulty == sails.local.constant.challenges.difficulty.hard %}\n        {% set diff = 'hard' %}\n    {% endif %}\n    <div class=\"em_common_content em_language_choice\">\n        <div class=\"row marginbottom40\">\n            <div class=\"col-12 center\">\n                {% if challenge.difficulty == sails.local.constant.challenges.difficulty.easy %}\n                    <h2 class=\"easy\">Easy: {{ challenge.name }}</h2>\n                {% endif %}\n                {% if challenge.difficulty == sails.local.constant.challenges.difficulty.medium %}\n                    <h2 class=\"medium\">Medium: {{ challenge.name }}</h2>\n                {% endif %}\n                {% if challenge.difficulty == sails.local.constant.challenges.difficulty.hard %}\n                    <h2 class=\"hard\">Hard: {{ challenge.name }}</h2>\n                {% endif %}\n                <h3 class=\"f300\">How do you plan on crushing this challenge?</h3>\n            </div>\n        </div>\n        <div class=\"row icons get-versions\">\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/js\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/js.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>JavaScript</h4>\n                <h6 class=\"version\" data-langname=\"node\">Node </h6>\n                <span class=\"badge badge-{{ ('js' in solved) ? diff : 'light' }}\">{{ ('js' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/python\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/python.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Python</h4>\n                <h6 class=\"version\" data-langname=\"python3\"></h6>\n                <span class=\"badge badge-{{ ('python' in solved) ? diff : 'light' }}\">{{ ('python' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/go\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/go.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Go</h4>\n                <h6 class=\"version\" data-langname=\"go\"></h6>\n                <span class=\"badge badge-{{ ('go' in solved) ? diff : 'light' }}\">{{ ('go' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/c\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/c.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>C</h4>\n                <h6 class=\"version\" data-langname=\"c\"></h6>\n                <span class=\"badge badge-{{ ('c' in solved) ? diff : 'light' }}\">{{ ('c' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/ruby\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/ruby.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Ruby</h4>\n                <h6 class=\"version\" data-langname=\"ruby\"></h6>\n                <span class=\"badge badge-{{ ('ruby' in solved) ? diff : 'light' }}\">{{ ('ruby' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/cpp\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/cpp.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>C++</h4>\n                <h6 class=\"version\" data-langname=\"cpp\"></h6>\n                <span class=\"badge badge-{{ ('cpp' in solved) ? diff : 'light' }}\">{{ ('cpp' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/cs\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/cs.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>C#</h4>\n                <h6 class=\"version\" data-langname=\"csharp\"></h6>\n                <span class=\"badge badge-{{ ('cs' in solved) ? diff : 'light' }}\">{{ ('cs' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/php\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/php.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>PHP</h4>\n                <h6 class=\"version\" data-langname=\"php\"></h6>\n                <span class=\"badge badge-{{ ('php' in solved) ? diff : 'light' }}\">{{ ('php' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/swift\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/swift.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Swift</h4>\n                <h6 class=\"version\" data-langname=\"swift\"></h6>\n                <span class=\"badge badge-{{ ('swift' in solved) ? diff : 'light' }}\">{{ ('swift' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/java\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/java.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Java</h4>\n                <h6 class=\"version\" data-langname=\"java\"></h6>\n                <span class=\"badge badge-{{ ('java' in solved) ? diff : 'light' }}\">{{ ('java' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/rust\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/rust.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Rust</h4>\n                <h6 class=\"version\" data-langname=\"rust\"></h6>\n                <span class=\"badge badge-{{ ('rust' in solved) ? diff : 'light' }}\">{{ ('rust' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/julia\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/julia.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Julia</h4>\n                <h6 class=\"version\" data-langname=\"julia\"></h6>\n                <span class=\"badge badge-{{ ('julia' in solved) ? diff : 'light' }}\">{{ ('julia' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/bash\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/bash.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Bash</h4>\n                <h6 class=\"version\" data-langname=\"bash\"></h6>\n                <span class=\"badge badge-{{ ('bash' in solved) ? diff : 'light' }}\">{{ ('bash' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/perl\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/perl.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Perl</h4>\n                <h6 class=\"version\" data-langname=\"perl\"></h6>\n                <span class=\"badge badge-{{ ('perl' in solved) ? diff : 'light' }}\">{{ ('perl' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/kotlin\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/kotlin.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Kotlin</h4>\n                <h6 class=\"version\" data-langname=\"kotlin\"></h6>\n                <span class=\"badge badge-{{ ('kotlin' in solved) ? diff : 'light' }}\">{{ ('kotlin' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/haskell\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/haskell.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Haskell</h4>\n                <h6 class=\"version\" data-langname=\"haskell\"></h6>\n                <span class=\"badge badge-{{ ('haskell' in solved) ? diff : 'light' }}\">{{ ('haskell' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div>\n            <div class=\"col-4 col-sm-3 col-md-2\">\n                <a href=\"/challenges/{{ challenge.challenge_id }}/nim\">\n                    <img src=\"/images/lang_icons/{{ challenge.difficulty_name }}/nim.svg\" class=\"img-fluid\" />\n                </a>\n                <h4>Nim</h4>\n                <h6 class=\"version\" data-langname=\"nim\"></h6>\n                <span class=\"badge badge-{{ ('nim' in solved) ? diff : 'light' }}\">{{ ('nim' in solved) ? 'Solved' : 'Unsolved' }}</span>\n            </div> \n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/challenges/home.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}Coding Challenges | EMKC{% endblock %}\n{% block desc %}Test out your skills in various challenges using one of 17 available languages.{% endblock %}\n{% block content %}\n    <div class=\"em_common_content em_challenges_list\">\n        <div class=\"row marginbottom20\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">Challenges</h4>\n\n                <p>\n                    Welcome to Knowledge Center challenges, a place to test out your skills in one of 17 languages\n                    of your choosing on a number of different practical tests. Points are awarded based on difficulty.\n                    You can complete the challenge up to 17 times (one for each available language). New challenges are\n                    being added all the time.\n                </p>\n            </div>\n        </div>\n\n        <div class=\"row\">\n            <div class=\"col-12 easy\">\n                <h5>Easy (+10 pts)</h5>\n                <div class=\"row challenge_list\">\n                    {% for challenge in easy %}\n                        <div class=\"col-12 col-sm-4\">\n                            <a href=\"/challenges/choose_language/{{ challenge.challenge_id }}\" class=\"challenge\">\n                                <div class=\"title\">\n                                    {% if challenge.solution %}\n                                        <span class=\"badge badge-easy\">Solved</span>\n                                    {% else %}\n                                        <span class=\"badge badge-light\">Unsolved</span>\n                                    {% endif %}\n                                    <span class=\"text\">{{ challenge.name }}</span>\n                                </div>\n                                <div class=\"description\">\n                                    {{ challenge.description }}\n                                </div>\n                            </a>\n                        </div>\n                    {% endfor %}\n                </div>\n            </div>\n            <div class=\"col-12 medium\">\n                <h5>Medium (+30 pts)</h5>\n                <div class=\"row challenge_list\">\n                    {% for challenge in medium %}\n                        <div class=\"col-12 col-sm-4\">\n                            <a href=\"/challenges/choose_language/{{ challenge.challenge_id }}\" class=\"challenge\">\n                                <div class=\"title\">\n                                    {% if challenge.solution %}\n                                        <span class=\"badge badge-medium\">Solved</span>\n                                    {% else %}\n                                        <span class=\"badge badge-light\">Unsolved</span>\n                                    {% endif %}\n                                    <span class=\"text\">{{ challenge.name }}</span>\n                                </div>\n                                <div class=\"description\">\n                                    {{ challenge.description }}\n                                </div>\n                            </a>\n                        </div>\n                    {% endfor %}\n                </div>\n            </div>\n            <div class=\"col-12 hard\">\n                <h5>Hard (+50 pts)</h5>\n                <div class=\"row challenge_list\">\n                    {% for challenge in hard %}\n                        <div class=\"col-12 col-sm-4\">\n                            <a href=\"/challenges/choose_language/{{ challenge.challenge_id }}\" class=\"challenge\">\n                                <div class=\"title\">\n                                    {% if challenge.solution %}\n                                        <span class=\"badge badge-hard\">Solved</span>\n                                    {% else %}\n                                        <span class=\"badge badge-light\">Unsolved</span>\n                                    {% endif %}\n                                    <span class=\"text\">{{ challenge.name }}</span>\n                                </div>\n                                <div class=\"description\">\n                                    {{ challenge.description }}\n                                </div>\n                            </a>\n                        </div>\n                    {% endfor %}\n                </div>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/community/about.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}About Engineer Man Knowledge Center{% endblock %}\n{% block content %}\n    <div class=\"em_common_content container\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">About Engineer Man Knowledge Center</h4>\n\n                <p>\n                    The Engineer Man Knowledge Center is a project by <a href=\"https://github.com/ebrian\" target=\"_blank\">Engineer Man</a>\n                    and other <a href=\"https://github.com/engineer-man/emkc/graphs/contributors\" target=\"_blank\">collaborators</a> designed\n                    to create a permanent knowledge resource for the people of Discord and the YouTube channel. The platform has drawn\n                    influence from the positive parts of Stack Exchange's Q&A and community systems as well as the discussion\n                    format of Reddit.\n                </p>\n\n                <p>\n                    The need for a Knowledge Center came about when our Discord server was flooded with people, questions,\n                    resources, ideas, and discussion. It was not practical to continue operating in that way on a service\n                    that was not built for what we were using it for.\n                </p>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/community/home.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}Community Resources | EMKC{% endblock %}\n{% block content %}\n    <div class=\"em_community_map\">\n        <div class=\"row\">\n            <div class=\"col-12 col-sm-3\">\n                <h6 class=\"f700\">Knowledge Center</h6>\n                <div class=\"link_list\">\n                    <a href=\"/community/about\">About</a>\n                </div>\n            </div>\n            <div class=\"col-12 col-sm-3\">\n                <h6 class=\"f700\">Power System</h6>\n                <div class=\"link_list\">\n                    <a href=\"/community/power\">How to Increase Power</a>\n                </div>\n            </div>\n            <div class=\"col-12 col-sm-3\">\n                <h6 class=\"f700\">Language Resources</h6>\n                <div class=\"link_list\">\n                    <a href=\"https://www.reddit.com/r/engineerman\" target=\"_blank\">All</a>\n                    <a href=\"https://www.reddit.com/r/engineerman/search/?q=assembly&restrict_sr=1\">Assembly</a>\n                    <a href=\"https://www.reddit.com/r/engineerman/search/?q=bash&restrict_sr=1\">Bash</a>\n                    <a href=\"https://www.reddit.com/r/engineerman/search/?q=c&restrict_sr=1\">C</a>\n                    <a href=\"https://www.reddit.com/r/engineerman/search/?q=cpp&restrict_sr=1\">C++</a>\n                    <a href=\"https://www.reddit.com/r/engineerman/search/?q=go&restrict_sr=1\">Go</a>\n                    <a href=\"https://www.reddit.com/r/engineerman/search/?q=javascript&restrict_sr=1\">JavaScript</a>\n                    <a href=\"https://www.reddit.com/r/engineerman/search/?q=node.js&restrict_sr=1\">Node.js</a>\n                    <a href=\"https://www.reddit.com/r/engineerman/search/?q=python&restrict_sr=1\">Python</a>\n                </div>\n            </div>\n            <div class=\"col-12 col-sm-3\">\n                <h6 class=\"f700\">Engineer Man</h6>\n                <div class=\"link_list\">\n                    <a href=\"https://www.youtube.com/engineerman\" target=\"_blank\">YouTube Channel</a>\n                    <a href=\"https://engineerman.org/discord\" target=\"_blank\">Discord Server</a>\n                </div>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/community/power.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}How To Gain Power | EMKC{% endblock %}\n{% block content %}\n    <div class=\"em_common_content em_power_system container\">\n        <div class=\"row marginbottom40\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">\n                    <i class=\"fa fa-bolt\"></i>\n                    Power System\n                </h4>\n\n                <p>\n                    The power system is a system which measures a person's meaningful contributions to the\n                    Engineer Man Community as well as recognize people for their knowledge in various regards.\n                    With more power comes more recognition and privileges in the Knowledge Center,\n                    recognition on Discord, moderation abilities, secret functionality, and more.\n                    You can earn power by people recognizing your contributions, finishing challenges, and winning\n                    official Engineer Man contests.\n                </p>\n            </div>\n        </div>\n        <div class=\"row marginbottom20\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">\n                    <i class=\"fa fa-rocket\"></i>\n                    Knowledge Community Ranks\n                </h4>\n            </div>\n        </div>\n        <div class=\"row marginbottom40\">\n            <div class=\"col-6 col-md-3\">\n                <div class=\"tier_circle novice\">\n                    <div class=\"wrapper\">\n                        <div class=\"tier\">Novice</div>\n                        <div class=\"score\">40+</div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"col-6 col-md-3\">\n                <div class=\"tier_circle hero\">\n                    <div class=\"wrapper\">\n                        <div class=\"tier\">Hero</div>\n                        <div class=\"score\">300+</div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"col-6 col-md-3\">\n                <div class=\"tier_circle master\">\n                    <div class=\"wrapper\">\n                        <div class=\"tier\">Master</div>\n                        <div class=\"score\">1,000+</div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"col-6 col-md-3\">\n                <div class=\"tier_circle legend\">\n                    <div class=\"wrapper\">\n                        <div class=\"tier\">Legend</div>\n                        <div class=\"score\">5,000+</div>\n                    </div>\n                </div>\n            </div>\n        </div>\n        <div class=\"row marginbottom10\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">\n                    <i class=\"fa fa-piggy-bank\"></i>\n                    How Power Is Earned\n                </h4>\n            </div>\n        </div>\n        <div class=\"row marginbottom20\">\n            <div class=\"col-12 col-lg-8\">\n                <div class=\"power_list\">\n                    <h5 class=\"heading\">Contests</h5>\n                    <p class=\"accent_text\">\n                        Winner is defined as the shortest solution that was submitted the quickest. Placing\n                        top 3 also earns you the participation points. Participation points (50) will\n                        only be awarded once per contest.\n                    </p>\n                    <div class=\"item\">\n                        <div>\n                            Place #1 in a contest (overall)\n                        </div>\n                        <span>+500</span>\n                    </div>\n                    <div class=\"item\">\n                        <div>\n                            Place #2 in a contest (overall)\n                        </div>\n                        <span>+200</span>\n                    </div>\n                    <div class=\"item\">\n                        <div>\n                            Place #3 in a contest (overall)\n                        </div>\n                        <span>+75</span>\n                    </div>\n                    <div class=\"item\">\n                        <div>\n                            Place #1 in a contest (per language)\n                        </div>\n                        <span>+50</span>\n                    </div>\n                    <div class=\"item\">\n                        <div>\n                            Participate in a contest (submit a solution)\n                        </div>\n                        <span>+50</span>\n                    </div>\n\n                    <h5 class=\"heading\">Challenges</h5>\n                    <p class=\"accent_text\">\n                        Points are awarded per language and per challenge.\n                    </p>\n                    <div class=\"item\">\n                        <div>\n                            Finish hard difficulty challenges\n                        </div>\n                        <span>+50</span>\n                    </div>\n                    <div class=\"item\">\n                        <div>\n                            Finish medium difficulty challenges\n                        </div>\n                        <span>+30</span>\n                    </div>\n                    <div class=\"item\">\n                        <div>\n                            Finish easy difficulty challenges\n                        </div>\n                        <span>+10</span>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/contests/contest.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}Coding Contest: {{ contest.name|e }} | EMKC{% endblock %}\n{% block content %}\n    <div class=\"em_common_content em_contests_contest container\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <div\n                    id=\"react_contest_contest\"\n                    data-contest=\"{{ contest|json_encode|e }}\"\n                    data-cases=\"{{ cases|json_encode|e }}\"\n                    data-submissions=\"{{ submissions|json_encode|e }}\"\n                ></div>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/contests/home.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}Weekly Contests | EMKC{% endblock %}\n{% block desc %}Got what it takes to create the shortest possible solution for the weekly contest? Give it a shot!{% endblock %}\n{% block content %}\n    <div class=\"em_common_content em_contests_home container\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <h4 class=\"f300 green\">Contests</h4>\n\n                <p>\n                    The Engineer Man Knowledge Center hosts contests weekly which are done in a Code Golf format.\n                    For those not familiar with Code Golf, it basically means that the winner of the contest is the person\n                    who can accomplish the given objective with the least amount of code, measured in bytes.\n                </p>\n\n                <p>\n                    Supported languages are those which <a href=\"https://github.com/engineer-man/piston\" target=\"_blank\">Piston</a> supports.\n                    To request new languages,\n                    submit a request in #emkc-felix-piston on <a href=\"https://discord.gg/engineerman\">Discord</a>. Our intent\n                    is to add proper golfing languages over time as well as a separate leaderboard for these languages.\n                </p>\n\n                <h5 class=\"f300 green\">Overview</h5>\n\n                <ol>\n                    <li>\n                        Contests start at 12:00pm CDT (5:00pm UTC) on Sundays and run for 3 days ending at 12:00pm CDT (5:00pm UTC) on Wednesdays.\n                    </li>\n                    <li>\n                        You can update your solution as many times as you want during the contest period. Submitting a solution\n                        that is shorter than your last submitted solution will result in the submitted time changed. This is\n                        important to understand because tiebreakers are resolved by the oldest solution.\n                    </li>\n                    <li>\n                        Points are awarded to the shortest solutions that meet the objective both overall and per language. If there\n                        are solutions that are the same length, the solution submitted the earliest will take precedent.\n                        Please see <a href=\"/community/power\">how to gain power</a> for more information.\n                    </li>\n                    <li>\n                        Leading and trailing whitespace is automatically trimmed before calculating the number of bytes used.\n                    </li>\n                    <li>\n                        Inputs are provided as command line arguments (ARGV) and standard input (STDIN) with each\n                        input separated by a newline character, you may use either one.\n                    </li>\n                </ol>\n\n                <h5 class=\"f300 green\">Rules</h5>\n\n                <ol>\n                    <li>\n                        No sharing solutions or discussing approach during the contest period.\n                    </li>\n                    <li>\n                        Submitted solutions must pass automated code execution before they are recorded as a contest submission.\n                        This is done using the <a href=\"https://github.com/engineer-man/piston\" target=\"_blank\">Piston</a> engine.\n                    </li>\n                    <li>\n                        For those using Bash, you can use any of the GNU coreutils as well as sed and awk. You may not call\n                        into any of the other contest languages (julia, perl, python, etc.).\n                    </li>\n                    <li>\n                        Don't submit duplicate solutions for similar languages (e.g. c/c++, js/ts/deno, etc).\n                    </li>\n                    <li>\n                        Solutions which depend on RNG to pass are not allowed.\n                    </li>\n                </ol>\n\n                <hr />\n\n                <div class=\"active\">\n                    <h4 class=\"f300 green\">Active Contests</h4>\n                    {% for contest in active_contests %}\n                        <a href=\"{{ contest.url }}\" class=\"contest\">\n                            <div class=\"name\">{{ contest.name }}</div>\n                            <p>\n                                Code Golf style contest. Click for more info or to submit solutions.\n                            </p>\n                            <div class=\"time_left\">\n                                Active Dates: {{ contest.start_date|date('F j, Y') }} - {{ contest.end_date|date('F j, Y') }}\n                                ({{ contest.time_left }} left)\n                            </div>\n                            <div class=\"solutions\">\n                                Total Solutions: {{ contest.submissions|length }}\n                                <div>\n                                    {% for submission in contest.submissions %}\n                                        <img src=\"{{ req.local.constant.cdn_url ~ submission.user.avatar_url }}\" />\n                                    {% endfor %}\n                                </div>\n                            </div>\n                        </a>\n                    {% else %}\n                        There are no active contests at this time.\n                    {% endif %}\n                </div>\n\n                <div class=\"past\">\n                    <h4 class=\"f300 green\">Past Contests</h4>\n                    {% for contest in past_contests %}\n                        <a href=\"{{ contest.url }}\" class=\"contest\">\n                            <div class=\"name\">{{ contest.name }}</div>\n                            <p>\n                                Code Golf style contest. Click to view solutions.\n                            </p>\n                            <div class=\"time_left\">\n                                Active Dates: {{ contest.start_date|date('F j, Y') }} - {{ contest.end_date|date('F j, Y') }}\n                                (Finished)\n                            </div>\n                            <div class=\"solutions\">\n                                Total Solutions: {{ contest.solutions }}\n                                <div>\n                                    {% for participant in contest.participants %}\n                                        <img src=\"{{ req.local.constant.cdn_url ~ participant }}\" />\n                                    {% endfor %}\n                                </div>\n                            </div>\n                        </a>\n                    {% else %}\n                        There are no pasts contests at this time.\n                    {% endif %}\n                </div>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/home/fourohfour.twig",
    "content": "{% extends 'master.twig' %}\n{% block content %}\n    <div style=\"text-align: center; padding: 60px 15px;\">\n        <img src=\"/images/404.png\" style=\"max-width: 384px; width: 100%; height: auto;\" />\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/home/home.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <div class=\"em_common_content container\">\n        <div class=\"row marginbottom20\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">Top {{ users|length }} Engineers on Planet Earth</h4>\n            </div>\n        </div>\n        <div class=\"row em_top_members\">\n            <div class=\"col-12\">\n                {% for user in users %}\n                    {% set color = '#000' %}\n                    {% if user.score >= 40 %}\n                        {% set color = '#79ACBF' %}\n                    {% endif %}\n                    {% if user.score >= 300 %}\n                        {% set color = '#7D9DC5' %}\n                    {% endif %}\n                    {% if user.score >= 1000 %}\n                        {% set color = '#ACB2E4' %}\n                    {% endif %}\n                    {% if user.score >= 5000 %}\n                        {% set color = '#D2ACE4' %}\n                    {% endif %}\n                    {% set max_score = users[0].score %}\n                    <a href=\"/@{{ user.username }}\" class=\"user_row\">\n                        <div class=\"score_progress\" style=\"background: {{ color }}; width: {{ (user.score / max_score) * 100 }}%;\"></div>\n                        <div class=\"picture\">\n                            <img src=\"{{ req.local.constant.cdn_url ~ user.avatar_url }}\" />\n                        </div>\n                        <div class=\"name\">\n                            <div class=\"wrapper\">\n                                {{ user.display_name|e }}\n                                {% if user.is_staff %}\n                                    <span class=\"badge badge-primary\">Staff</span>\n                                {% endif %}\n                            </div>\n                        </div>\n                        <div class=\"power\">\n                            <div class=\"wrapper\">\n                                <i class=\"fa fa-bolt\"></i>\n                                {{ user.score }}\n                            </div>\n                        </div>\n                    </a>\n                {% endfor %}\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/home/login.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <a href=\"/auth/discord\" class=\"btn btn-success btn-md\">Discord</a>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/home/privacy.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}Privacy Policy | EMKC{% endblock %}\n{% block content %}\n    <div class=\"em_common_content em_power_system container\">\n        <div class=\"row marginbottom40\">\n            <div class=\"col-12\">\n                <h3>Privacy Policy</h3>\n                <p>This privacy notice tells you about the information we collect from you when you use our website. </p>\n                <h4 class=\"f300\">Who are we?</h4>\n                <p>EMKC is operated by EngineerMan. You can contact us by email at <a href=\"mailto:em@engineerman.org\">em@engineerman.org</a>. </p>\n                <p>We are not required to have a data protection officer, so any enquiries about our use of your personal data should be addressed to the contact details above.</p>\n                <h4 class=\"f300\">How we use your information</h4>\n                <p>Certain visitors to our websites choose to interact with EMKC in ways that require EMKC to gather personally-identifying information. The amount and type of information that EMKC gathers depends on the nature of the interaction. For example, when you log in to EMKC using Discord, Discord will transmit your email address. In this case, EMKC collects such information in order to fulfill the purpose of the visitor’s interaction with EMKC.</p>\n                <p>Like most website operators, EMKC collects non-personally-identifying information of the sort that web browsers and servers typically make available, such as the browser type, language preference, referring site, and the date and time of each visitor request. Our purpose in collecting non-personally identifying information is to better understand how our visitors use the website.</p>\n                <p>Your information is stored on our website and on our cloud servers, both of which are based within the United States.</p>\n                <p>We keep your user information for as long as you have a user account with us.</p>\n                <p>A visitor's IP address may be logged within our system, typically for debugging purposes, separate from our system application databases. The IP address may remain stored within our logs for up to 3 months.</p>\n                <h4 class=\"f300\">Account deletion</h4>\n                <p>You may decide to delete your account at any time. You can do so by sending an email to the contact information provided above.</p>\n                <h4 class=\"f300\">Cookies</h4>\n                <p>When you use our website to browse our content and view the information we make available, cookies are used by us to allow the website to function.</p>\n                <p>The cookies we use are strictly necessary for our website to function. EMKC visitors who do not wish to have cookies placed on their computers should set their browsers to refuse cookies before using our websites, with the drawback that certain features of our websites may not function properly without the aid of cookies.</p>\n                <h4 class=\"f300\">Information Protection</h4>\n                <p>EMKC takes all measures reasonably necessary to protect against the unauthorized access, use, alteration or destruction of potentially personally-identifying and personally-identifying information</p>\n                <h4 class=\"f300\">Your rights as a data subject</h4>\n                <p>You can ask us what information we hold about you, and you can ask us to correct it if it is inaccurate. If we have asked for your consent to process your personal data, you may withdraw that consent at any time.</p>\n                <p>To submit a request regarding your personal data, please use the contact information provided above in the Who Are We section of this policy.</p>\n                <p>This policy was last updated on February 25th 2019.</p>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/master.twig",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-28939284-9\"></script>\n        <script>\n            window.dataLayer = window.dataLayer || [];\n            function gtag(){dataLayer.push(arguments);}\n            gtag('js', new Date());\n            gtag('config', 'UA-28939284-9');\n        </script>\n\n        <title>{% block title %}Engineer Man Knowledge Center{% endblock %}</title>\n\n        <meta name=\"KEYWORDS\" content=\"\" />\n        <meta name=\"DESCRIPTION\" content=\"{% block desc %}Engineer Man Knowledge Center or EMKC is an intelligent new platform for quality discussion, questions, challenges, and learning.{% endblock %}\" />\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n\n        <meta property=\"og:title\" content=\"{% block title %}Engineer Man Knowledge Center{% endblock %}\"/>\n        <meta property=\"og:image\" content=\"{{ sails.config.base_url ~ '/images/icon_square_64.png' }}\"/>\n        <meta property=\"og:description\" content=\"{% block desc %}Engineer Man Knowledge Center or EMKC is an intelligent new platform for quality discussion, questions, challenges, and learning.{% endblock %}\"/>\n        <meta property=\"og:url\" content=\"{{ sails.config.base_url ~ req.url }}\" />\n\n        {% block css %}\n            <link href=\"//fonts.googleapis.com/css?family=Lato:100,300,400,700,900\" rel=\"stylesheet\" />\n            <link href=\"//use.fontawesome.com/releases/v5.2.0/css/all.css\" rel=\"stylesheet\" />\n            <link href=\"/lib/bootstrap/bootstrap.min.css\" rel=\"stylesheet\" />\n            <link href=\"//cdn.quilljs.com/1.0.0/quill.snow.css\" rel=\"stylesheet\">\n            <link href=\"/lib/highlightjs/atom-one-dark.css\" rel=\"stylesheet\">\n            <link href=\"/lib/webpack/main.bundle.css?{{ sails.local.epoch }}\" rel=\"stylesheet\" />\n        {% endblock %}\n\n        {% block js %}\n            <script src=\"/lib/jquery/jquery-3.0.0.min.js\"></script>\n            <script src=\"/lib/popper/popper.min.js\"></script>\n            <script src=\"/lib/bootstrap/bootstrap.min.js\"></script>\n            <script src=\"/lib/highlightjs/highlight.pack.js\"></script>\n            <script src=\"/lib/highlightjs/highlight-ln.js\"></script>\n            <script src=\"/lib/bootbox/bootbox.js\"></script>\n        {% endblock %}\n\n        <script>\n            ctx = {\n                cdn_url: '{{ req.local.constant.cdn_url }}',\n                user_id: +'{{ req.local.user_id ? req.local.user_id : 0 }}',\n                username: {{ req.local.user.username|json_encode }},\n                is_staff: +'{{ req.local.user and req.local.user.is_staff ? 1 : 0 }}',\n            };\n        </script>\n\n        <link rel=\"icon\" type=\"image/x-icon\" href=\"/images/icon_circle_64.png\" />\n    </head>\n    <body>\n        <div class=\"em_container\" style=\"position: relative;\">\n            <div class=\"em_menu\">\n                <div class=\"mobile_expand\" onclick=\"mobile_nav.open()\">\n                    <i class=\"fa fa-bars\"></i>\n                </div>\n                <div class=\"brand_icon\">\n                    <a href=\"/\">\n                        <img src=\"/images/icon_circle_64.png\" />\n                    </a>\n                </div>\n                <div class=\"main_links\">\n                    <a href=\"/challenges\">Challenges</a>\n                    <a href=\"/contests\">Contests</a>\n                    <a href=\"/community\">Community</a>\n                    <div class=\"dropdown\">\n                        <a class=\"dropdown-toggle\" data-toggle=\"dropdown\">\n                            Tools\n                        </a>\n                        <div class=\"dropdown-menu\">\n                            <a class=\"dropdown-item\" href=\"/scripts\">CLI Scripts</a>\n                            <a class=\"dropdown-item\" href=\"/snippets\">New Snippet</a>\n                            {% if req.local.user_id %}\n                                <a class=\"dropdown-item\" href=\"/snippets/mine\">My Snippets</a>\n                            {% endif %}\n                        </div>\n                    </div>\n                </div>\n                <div class=\"search\" style=\"visibility: hidden;\">\n                    <input type=\"text\" placeholder=\"Search...\" />\n                </div>\n                {% if req.local.user_id %}\n                    <div class=\"user_meta\">\n                        <i class=\"fa fa-bolt\"></i>\n                        <span class=\"f900\">{{ req.local.user.score }}</span>\n                        <div class=\"dropdown\">\n                            <img\n                                src=\"{{ sails.local.constant.cdn_url }}{{ req.local.user.avatar_url }}\"\n                                class=\"dropdown-toggle\"\n                                data-toggle=\"dropdown\" />\n                            <div class=\"dropdown-menu dropdown-menu-right\">\n                                <h6 class=\"dropdown-header\">{{ req.local.user.username }}</h6>\n                                <a class=\"dropdown-item\" href=\"/@{{ req.local.user.username }}\">Profile</a>\n                                {% if req.local.user.is_staff %}\n                                    <a class=\"dropdown-item\" href=\"/admin\">Staff Area</a>\n                                {% endif %}\n                                <div class=\"dropdown-divider\"></div>\n                                <a class=\"dropdown-item\" href=\"/logout\">Logout</a>\n                                {% if req.session.old_id %}\n                                    <a class=\"dropdown-item\" href=\"/logout_as\">Logout Admin</a>\n                                {% endif %}\n                            </div>\n                        </div>\n                    </div>\n                {% else %}\n                    <div class=\"login\">\n                        <a onclick=\"login.open()\">Login</a>\n                    </div>\n                {% endif %}\n            </div>\n\n            {% if sails.twig.starts_with(req.path, '/admin') and req.local.user.is_staff %}\n                <div class=\"em_staff_container\">\n                    Staff Stuff:\n                    <a href=\"/admin/users\">Users</a> |\n                    <a href=\"/admin/contests\">Contests</a> |\n                    <a href=\"/admin/challenges\">Challenges</a> |\n                    <a href=\"/admin/piston\">Piston</a>\n                </div>\n            {% endif %}\n\n            {% block content %}{% endblock %}\n\n            <div class=\"f700 em_footer\">\n                <a href=\"/privacy\">Privacy Policy</a>\n            </div>\n        </div>\n        <div id=\"react_mobile_nav\"></div>\n        {% if not req.local.user_id %}\n            <div id=\"react_login\"></div>\n        {% endif %}\n        {% block bundles %}{% endblock %}\n        <script src=\"/lib/webpack/react.bundle.js?{{ sails.local.epoch }}\"></script>\n        <script src=\"/lib/webpack/main.bundle.js?{{ sails.local.epoch }}\"></script>\n    </body>\n</html>\n"
  },
  {
    "path": "platform/views/merch/stickers.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <script src=\"https://www.paypalobjects.com/api/checkout.js\"></script>\n    <div class=\"em_common_content em_stickers\">\n        <div class=\"row marginbottom40\">\n            <div class=\"col-12 col-sm-7 col-md-6 offset-md-1\">\n                <div\n                    id=\"react_stickers\"\n                    data-env=\"{{ (sails.config.environment == 'production' ? 'production' : 'sandbox')|json_encode|e }}\"\n                    data-paypal_id=\"{{ sails.config.paypal.id|json_encode|e }}\"\n                    data-options=\"{{ options|json_encode|e }}\"\n                ></div>\n            </div>\n            <div class=\"col-12 col-sm-5 col-md-4\">\n                <p>\n                    <span class=\"f700\">Batch Notes:</span>\n                    <ul>\n                        <li>\n                            First batch of stickers is 300 in total and are being sold at cost (possibly even a loss).\n                            If you're able to see this page, stickers are still available.\n                        </li>\n                        <li>\n                            If you are already an Engineer Man supporter,\n                            have donated during stream, have Nitro boosted our Discord server, have been granted\n                            the role of Discord Hero, or attained the level of\n                            EMKC Master, and have not yet received a sticker, please message EngineerMan#0001 on Discord for\n                            a coupon code good for two stickers.\n                        </li>\n                    </ul>\n                </p>\n\n                <p>\n                    <span class=\"f700\">Order Notes:</span>\n                    <ul>\n                        <li>Make sure your address is accurate and exactly as it should appear on an envelope.</li>\n                        <li>Checkout button will appear once the form is filled out.</li>\n                        <li>\n                            Stickers are shipped from Florida, USA. Please allow 3 days for processing, 2-3 days for\n                            domestic delivery, 7-14 days for international delivery.\n                        </li>\n                        <li>After order submission, you'll receive an Order ID. Please record this in case you need to reference this order.</li>\n                    </ul>\n                </p>\n\n                <p>\n                    <span class=\"f700\">Privacy Notes:</span>\n                    <ul>\n                        <li>No payment information is received or stored by EMKC. Payment is handled entirely by PayPal.</li>\n                        <li>Name and address is only stored until your stickers have shipped and then it is deleted.</li>\n                        <li>Your email is used only to contact you if for some reason there is a problem processing your order.</li>\n                    </ul>\n                </p>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/profiles/view.twig",
    "content": "{% extends 'master.twig'%}\n{% block title %}{{ user.display_name|e }} - EMKC Member{% endblock %}\n{% block content %}\n    <div class=\"em_common_content em_profile container\">\n        <div class=\"content\">\n            <div class=\"left\">\n                <div class=\"padding\">\n                    <img src=\"{{ sails.local.constant.cdn_url }}{{ user.avatar_url }}\" class=\"avatar\" />\n                    <h4 class=\"f700\">{{ user.display_name }}</h4>\n                    <h4 class=\"f900\"><i class=\"fa fa-bolt\"></i> {{ user.score }}</h4>\n                    <hr />\n                    <p>\n                        <span class=\"f700\">Member Since</span><br />\n                        {{ user.created_at|date('m/d/Y') }}\n                    </p>\n                    <p>\n                        <span class=\"f700\">Challenges Solved</span><br />\n                        {{ stat_challenges }}\n                    </p>\n                    <p>\n                        <span class=\"f700\">Contests Entered</span><br />\n                        {{ stat_contests }}\n                    </p>\n                </div>\n            </div>\n            <div class=\"right\">\n                <h4 class=\"f300\">Awards</h4>\n\n                <div class=\"awards\">\n                    {% for award in awards %}\n                        <div class=\"award\">\n                            <div>\n                                <img\n                                    data-placement=\"bottom\"\n                                    title=\"{{ award.tooltip_text }}\"\n                                    src=\"/images/awards/{{ award.type }}.png\" />\n                            </div>\n                            <div class=\"count\">\n                                {{ award.count }}\n                            </div>\n                        </div>\n                    {% else %}\n                        This user has no awards yet.\n                    {% endif %}\n                </div>\n                <script>$('.award img').tooltip({container: '.awards'})</script>\n\n                <h4 class=\"f300\">Recent Solved Challenges</h4>\n\n                {% for challenge in challenges %}\n                    <div class=\"d-flex challenge\">\n                        <a href=\"/challenges/{{ challenge.challenge_id}}/{{ challenge.language }}\" class=\"flex-grow-1 {{ challenge.challenge.difficulty_name }}\">\n                            <p>\n                                {{ challenge.challenge.description }}\n                            </p>\n                            <span class=\"badge badge-light\">{{ challenge.language }}</span>\n                            <span class=\"badge badge-primary\">Solved on: {{ challenge.created_at|date('m/d/Y') }}</span>\n                        </a>\n                        {% if user_solved_challenges|contains(challenge) %}\n                            <a href=\"/@{{ user.username }}/challenges/{{ challenge.challenge_id}}/{{ challenge.language }}\" class=\"view_solution d-flex flex-column justify-content-center align-items-center\">\n                                <p>View</p>\n                                <p>Solution</p>\n                            </a>\n                        {% endif %}\n                    </div>\n                {% else %}\n                    This user has not solved any challenges.\n                {% endif %}\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/scripts/home.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <div class=\"em_wide_content\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">CLI Script Database</h4>\n\n                <table class=\"table table-sm table-dark\">\n                    <thead>\n                        <tr>\n                            <th scope=\"col\" class=\"center\" style=\"width: 80px;\">View</th>\n                            <th scope=\"col\">Title</th>\n                            <th scope=\"col\" style=\"width: 180px;\">Created</th>\n                        </tr>\n                    </thead>\n                    <tbody>\n                        {% for script in scripts %}\n                            <tr>\n                                <td class=\"center\">\n                                    <a href=\"{{ script.view_url }}\">View</a>\n                                </td>\n                                <td>{{ script.title }}</td>\n                                <td>{{ script.created_at|date('m/d/Y g:i a') }}</td>\n                            </tr>\n                        {% endfor %}\n                    </tbody>\n                </table>\n            </div>\n        </div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/scripts/view.twig",
    "content": "{% extends 'master.twig'%}\n{% block bundles %}\n    <script src=\"/lib/webpack/monaco.bundle.js?{{ sails.local.epoch }}\"></script>\n{% endblock %}\n{% block content %}\n    <div class=\"em_wide_content\">\n        <h4 class=\"f300\">{{ script.title }}</h4>\n        <div style=\"padding: 5px 10px; background: rgba(0,0,0,.5); font-family: monospace; margin-bottom: 10px;\">bash <(curl -sSf {{ sails.config.base_url }}/exec/{{ script.cli_script_id }})</div>\n        <div\n            id=\"react_cli_script\"\n            data-content=\"{{ script.content|json_encode|e }}\"\n            data-snip=\"{{ snippet.snip|json_encode|noscript|e }}\"\n        ></div>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/snippets/edit.twig",
    "content": "{% extends 'master.twig' %}\n{% block css %}\n    {{ parent() }}\n    <style>\n        body {\n            overflow-x: hidden;\n        }\n        .em_container {\n            background: #1E1E1E;\n        }\n    </style>\n{% endblock %}\n{% block bundles %}\n    <script src=\"/lib/webpack/monaco.bundle.js?{{ sails.local.epoch }}\"></script>\n{% endblock %}\n{% block content %}\n    <div\n        id=\"react_manage_snippet\"\n        data-mode=\"{{ mode|json_encode|e }}\"\n        data-language=\"{{ snippet.language|json_encode|e }}\"\n        data-snip=\"{{ snippet.snip|json_encode|noscript|e }}\"\n        data-user_id=\"{{ snippet.user_id|json_encode|e }}\"\n        data-hash=\"{{ snippet.hash|json_encode|e }}\"\n    ></div>\n{% endblock %}\n"
  },
  {
    "path": "platform/views/snippets/mine.twig",
    "content": "{% extends 'master.twig'%}\n{% block content %}\n    <div class=\"em_wide_content\">\n        <div class=\"row\">\n            <div class=\"col-12\">\n                <h4 class=\"f300\">\n                    My Snippets\n                    <a href=\"/snippets\">\n                        <i class=\"fa fa-plus green float-right\"></i>\n                    </a>\n                </h4>\n\n                {% if snippets.length > 0 %}\n                    <table class=\"table table-dark table-bordered table-sm table-hover\">\n                        <thead>\n                            <tr>\n                                <th style=\"width: 70px;\"></th>\n                                <th style=\"width: 120px;\">Language</th>\n                                <th style=\"width: 120px;\">Age</th>\n                                <th>Preview</th>\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {% for snippet in snippets %}\n                                <tr>\n                                    <td class=\"center\">\n                                        <nobr>\n                                            <a href=\"{{ snippet.url }}\" class=\"fas fa-eye\"></a>&nbsp;\n                                            <a href=\"/snippets/edit/{{ snippet.hash }}\" class=\"fas fa-pen\"></a>&nbsp;\n                                            <a href=\"#\"\n                                                class=\"confirm-delete fas fa-trash text-danger\"\n                                                data-hash=\"{{ snippet.hash }}\">\n                                            </a>\n                                        </nobr>\n                                    </td>\n                                    <td>{{ snippet.language }}</td>\n                                    <td>{{ snippet.time_ago }}</td>\n                                    <td style=\"color: #fff;\">\n                                        {{ snippet.snip|slice(0, 200)|e }}\n                                    </td>\n                                </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n                {% else %}\n                    You have not created any snippets.\n                {% endif %}\n            </div>\n        </div>\n    </div>\n{% endblock %}\n\n"
  },
  {
    "path": "platform/webpack.config.js",
    "content": "const path = require('path');\nconst MiniCSSExtractPlugin = require('mini-css-extract-plugin');\nconst MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');\n\nmodule.exports = {\n    entry: {\n        main: './resources/main.js',\n        monaco: './resources/monaco.js'\n    },\n    module: {\n        rules: [\n            {\n                test: /\\.(js|jsx)$/,\n                exclude: /node_modules/,\n                use: {\n                    loader: 'babel-loader'\n                }\n            },\n            {\n                test: /\\.less$/,\n                exclude: /node_modules/,\n                use: [\n                    {\n                        loader: MiniCSSExtractPlugin.loader,\n                        options: {\n                            publicPath: (resourcePath, context) => {\n                                return (\n                                    path.relative(\n                                        path.dirname(resourcePath),\n                                        context\n                                    ) + '/'\n                                );\n                            }\n                        }\n                    },\n                    {\n                        loader: 'css-loader'\n                    },\n                    {\n                        loader: 'less-loader'\n                    }\n                ]\n            },\n            {\n                test: /\\.css$/,\n                use: [\n                    {\n                        loader: 'style-loader'\n                    },\n                    {\n                        loader: 'css-loader'\n                    }\n                ]\n            },\n            {\n                test: /\\.ttf$/,\n                use: [\n                    {\n                        loader: 'file-loader'\n                    }\n                ]\n            }\n        ]\n    },\n    resolve: {\n        extensions: ['.js', '.jsx', '.json'],\n        modules: ['node_modules', path.resolve(__dirname, 'resources/')]\n    },\n    output: {\n        path: path.resolve(__dirname, 'public/lib/webpack'),\n        publicPath: '/lib/webpack/',\n        filename: '[name].bundle.js'\n    },\n    optimization: {\n        splitChunks: {\n            cacheGroups: {\n                react: {\n                    test: /[\\\\/]node_modules[\\\\/](react|react-dom)[\\\\/]/,\n                    name: 'react',\n                    chunks: 'initial'\n                }\n            }\n        },\n        sideEffects: false\n    },\n    plugins: [\n        new MiniCSSExtractPlugin({\n            filename: '[name].bundle.css'\n        }),\n        new MonacoWebpackPlugin()\n    ]\n};\n"
  },
  {
    "path": "readme.md",
    "content": "## Engineer Man Knowledge Center (emkc)\n\nThis is the official repo and project for the Engineer Man Knowledge Center. The official deployment of this project\nis located at https://emkc.org. Be sure to familiarize yourself with the contribution guidelines and project license\nif you plan to use this software.\n\n#### Install Instructions\n\nDocker is the preferred (and only supported) way to work with EMKC in development. EMKC is known to work on all\nLinux/macOS machines and Windows machines running either WSL or natively with Windows 10 Pro.\n\n-   `git clone https://github.com/engineer-man/emkc`\n-   `cd emkc`\n-   `./emkc init`\n-   `./emkc start`\n-   `./emkc rmig migrate`\n-   `./emkc stop` when done.\n-   `./emkc` to view a list of commands.\n\nOnce started, you can access the local version of the site at http://127.0.0.1:2005 (localhost:2005 for WSL).\n\n> **Note:** when using WSL, it is recommended to use the linux filesystem for better performance and fewer errors; however if you intend to use the windows filesystem, make sure to mount your windows volumes with metadata options since the MySQL Docker Container needs permissions to modify files in the volume. You can configure that automatically on WSL startup by adding `options = \"metadata\"` to /etc/wsl.conf under the [automount]\n> section (check https://devblogs.microsoft.com/commandline/automatically-configuring-wsl/)\n\n#### Local Config\n\nThere are two files needed to configure the application. Make sure to modify these with your own values. If\nthese files are not present, navigate to the project root and run `./emkc init`.\n\n-   App: `platform/config/local.js`\n-   DB Migrations: `platform/migrations/config.json`\n\n#### Contribution Guidelines\n\nAll contributions are reviewed to make sure they work, fit well with the design, and fit well with\nthe established code. BDFL is [realtux](https://github.com/realtux) who will do a final review and merge\nto master and deploy.\n\n-   Review the issues on GitHub and grab whichever you feel most comfortable doing\n-   Place code on a branch other than master/develop (Fork for non-org developers)\n-   Follow the style that is generally present with the project (details below)\n-   Use established tech in place (Bootstrap 4, React, etc.)\n-   Test to make sure everything works\n\n#### General Code Guidelines\n\n-   Prefer spaces over tabs\n-   120 character max line length for source\n-   PascalCase for classes, snake_case for everything else\n-   Use ES9 to the fullest extent possible\n-   Single quotes only\n-   In general just make code look like everything else\n\n#### License\n\nEngineer Man Knowledge Center is licensed under the permissive MIT license. License details can be found\nin the `license` file in the root of the project.\n"
  },
  {
    "path": "var/502/502.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <title>Engineer Man Knowledge Center</title>\n    </head>\n    <body style=\"background: #282C34; color: #fff; position: relative; height: 100vh\">\n        <div style=\"position: absolute; left: 50%; top: 40%; margin-left: -120px; margin-top: -70px; width: 240px; text-align: center;\">\n            <img src=\"/images/502_animated.gif\" style=\"width: 90px; height: 90px;\" />\n            <br />\n            Deploying new cool features.<br />\n            Refresh in a sec.\n        </div>\n    </body>\n</html>\n"
  },
  {
    "path": "var/docker/clean",
    "content": "rm -rf ./logs/*\nrm -rf ./mysql/*\nrm -rf ./redis/*\n"
  },
  {
    "path": "var/docker/config/mysqld.cnf",
    "content": "[mysqld]\nsymbolic-links=0\ninnodb_file_per_table=1\nsql_mode = \"\"\n\n[server]\n#general_log=1\n#general_log_file=/opt/emkc/var/docker/logs/sql.log\n"
  },
  {
    "path": "var/docker/init/db.sql",
    "content": "create database if not exists emkc;\n"
  },
  {
    "path": "var/docker/logs/.gitkeep",
    "content": ""
  },
  {
    "path": "var/docker/mysql/.gitkeep",
    "content": ""
  },
  {
    "path": "var/docker/redis/.gitkeep",
    "content": ""
  },
  {
    "path": "var/text/a.txt",
    "content": ""
  },
  {
    "path": "var/tmp/.gitkeep",
    "content": ""
  },
  {
    "path": "var/tmp/scripts.sql",
    "content": "insert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (21,1,1,1,'Disabling SELinux on CentOS 6','nano /etc/selinux/config\\r\\n# change SELINUX=enforcing to SELINUX=disabled\\r\\necho 0 > /selinux/enforce',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (22,1,1,1,'Get Uptime on Linux','uptime',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (3,1,1,1,'Install Git 2.6.2 on CentOS 6/7','sudo yum groupinstall -y \\'development tools\\'\\r\\nsudo yum install -y wget curl-devel expat-devel gettext-devel openssl-devel perl-devel zlib-devel\\r\\nwget https://cmd.bri.io/static/deps/3/git-2.6.2.tar.gz\\r\\ntar -zxf git-2.6.2.tar.gz\\r\\ncd git-2.6.2\\r\\nmake configure\\r\\n./configure --prefix=/usr\\r\\nmake all\\r\\nsudo make install',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (4,1,1,1,'Install Ruby 2.1.0 on CentOS 6/7','sudo yum groupinstall -y \\'development tools\\'\\r\\ngpg2 --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3\\r\\ncurl -L get.rvm.io | bash -s stable\\r\\nsource /etc/profile.d/rvm.sh\\r\\nrvm reload\\r\\nrvm install 2.1.0',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (5,1,1,1,'Burn DVD from the command line','wodim -eject -tao  speed=2 dev=/dev/sr0 -v -data isoname.iso',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (6,1,1,1,'Generate Private Key and CSR on CentOS 6/7','sudo yum install -y openssl\\r\\nopenssl genrsa -out server.key 2048\\r\\nopenssl req -new -sha256 -key server.key -out server.csr',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (7,1,1,1,'Resize Google Compute Engine VM Boot Disk','fdisk -l\\r\\n# take note of the starting sector\\r\\n\\r\\nfdisk /dev/sda\\r\\n# hit d to delete the partition\\r\\n# hit n for new partition\\r\\n# hit p for primary\\r\\n# hit 1 for partition number\\r\\n# type the starting sector and hit enter\\r\\n# hit enter to accept the end sector\\r\\n# hit w to write the partition table\\r\\n\\r\\nresize2fs /dev/sda1',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (8,1,1,1,'Create combined SSL chain file','# order matters\\r\\ncat yourcert.crt intermediate.crt root.crt yourkey.key > combined.pem',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (9,1,1,1,'Create and use a LUKS Volume','# create luks\\r\\ndd if=/dev/urandom of=/home/brian/file bs=1M count=512\\r\\nsudo cryptsetup -y luksFormat /home/brian/file\\r\\nsudo cryptsetup luksOpen /home/brian/file volume_name\\r\\nsudo mkfs.ext4 /dev/mapper/volume_name\\r\\n\\r\\n# mount\\r\\nsudo cryptsetup luksOpen /home/brian/file volume_name\\r\\nsudo mount /dev/mapper/volume_name /mount/point\\r\\n\\r\\n# close\\r\\nsudo umount /dev/mapper/volume_name\\r\\nsudo cryptsetup luksClose volume_name',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (10,1,1,1,'Install Python 2.7.3 on CentOS 6/7','sudo yum groupinstall -y \\'development tools\\'\\r\\nwget http://python.org/ftp/python/2.7.6/Python-2.7.6.tar.xz\\r\\nxz -d Python-2.7.6.tar.xz\\r\\ntar -xvf Python-2.7.6.tar\\r\\nrm -f Python-2.7.6.tar\\r\\ncd Python-2.7.6\\r\\n./configure\\r\\nmake && make altinstall\\r\\ncd ..',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (11,1,1,1,'Install Latest bmig on CentOS 6/7','sudo yum install -y gcc mysql-devel json-c-devel\\r\\ngit clone https://github.com/ebrian/bmig\\r\\ncd bmig\\r\\nmake\\r\\nsudo make install',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (12,1,1,1,'Install Latest bmig on Ubuntu','sudo apt-get install build-essential pkg-config git gcc libmysqlclient-dev libjson0-dev\\r\\ngit clone https://github.com/ebrian/bmig\\r\\ncd bmig\\r\\nmake\\r\\nsudo make install',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (13,1,1,1,'Install GCC 4.8.x on CentOS 6/7','wget http://people.centos.org/tru/devtools-2/devtools-2.repo -O /etc/yum.repos.d/devtools-2.repo\\r\\nyum install devtoolset-2-gcc devtoolset-2-gcc-c++ devtoolset-2-binutils\\r\\nscl enable devtoolset-2 bash',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (14,1,1,1,'Install Node 4.2.1 on CentOS 6/7','wget https://nodejs.org/dist/v4.2.1/node-v4.2.1-linux-x64.tar.gz\\r\\ntar -xzzvf node-v4.2.1-linux-x64.tar.gz\\r\\nrm -f node-v4.2.1-linux-x64.tar.gz\\r\\nmv node-v4.2.1-linux-x64 node4',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (15,1,1,1,'Install MySQL 5.5 on CentOS 6','rpm -Uvh https://mirror.webtatic.com/yum/el6/latest.rpm\\r\\nyum install -y mysql.`uname -i` yum-plugin-replace\\r\\nyum replace mysql --replace-with mysql55w\\r\\nyum install -y mysql55w mysql55w-server',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (16,1,1,1,'MySQL Table to CSV','select *\\r\\n  from table\\r\\n  into outfile \\'/tmp/file.csv\\'\\r\\n  fields terminated by \\',\\' optionally enclosed by \\'\\\"\\'\\r\\n  lines terminated by \\'\\\\n\\';',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (17,1,1,1,'Install Node 4.2.1 on Raspberry PI 2 B+','wget https://nodejs.org/dist/v4.2.1/node-v4.2.1-linux-armv6l.tar.gz\\r\\ntar -xzzvf node-v4.2.1-linux-armv6l.tar.gz\\r\\nrm -f node-v4.2.1-linux-armv6l.tar.gz\\r\\nmv node-v4.2.1-linux-armv6l node4\\r\\nln -s /root/node4/bin/node /usr/bin/node\\r\\nln -s /root/node4/bin/npm /usr/bin/npm',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (19,1,1,1,'TAR and GZip to GPG on the fly','# encrypt\\r\\nexport GPG_TTY=$(tty)\\r\\ntar zcf - whatever_folder | gpg --symmetric --cipher-algo aes256 -o whatever.gpg\\r\\n\\r\\n# decrypt\\r\\nexport GPG_TTY=$(tty)\\r\\ngpg -d whatever.gpg | tar xzf -',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (20,1,1,1,'Compress, Encrypt with GPG, and Split','# construct\\r\\nexport GPG_TTY=$(tty)\\r\\ntoday=$(date +%Y%m%d)\\r\\ntar zcf - folder1 folder2 folder3 \\\\\\r\\n    | gpg --symmetric --cipher-algo aes256 -o - \\\\\\r\\n    | split -b 2G -d -a 3 - backup.$today.gpg.\\r\\n\\r\\n# deconstruct\\r\\nexport GPG_TTY=$(tty)\\r\\ncat backup.20160607.gpg.* \\\\\\r\\n    | gpg -d -o - \\\\\\r\\n    | tar xzf -',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (23,1,1,1,'Install Node 6 on Centos 6/7','wget https://nodejs.org/dist/v6.3.0/node-v6.3.0-linux-x64.tar.gz\\r\\ntar -xzzvf node-v6.3.0-linux-x64.tar.gz\\r\\nrm -f node-v6.3.0-linux-x64.tar.gz\\r\\nmv node-v6.3.0-linux-x64 node6',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (24,1,1,1,'Wipe Drive Linux','# yes this is secure, stop being paranoid\\r\\n# https://digital-forensics.sans.org/blog/2009/01/15/overwriting-hard-drive-data/\\r\\n\\r\\ndd if=/dev/zero of=/dev/your_device bs=1M',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (26,1,1,1,'Create self-signed SSL Certificate','openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days XXX -nodes',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (27,1,1,1,'Bulk Crop Images','for f in *.jpg; do\\r\\n  convert $f -trim $f\\r\\ndone',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (28,1,1,1,'CentOS 6 TTY Auto Login','# open config\\r\\nnano /etc/init/tty.conf\\r\\n\\r\\n# replace this\\r\\nexec /sbin/mingetty $TTY\\r\\n\\r\\n# with this (replace username)\\r\\nexec /sbin/mingetty --autologin username $TTY',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (29,1,1,1,'CentOS 6 No TTY Screensaver','# open config\\r\\nnano /etc/rc.d/rc.local\\r\\n\\r\\n# add this line at the bottom\\r\\nsetterm -blank 0',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (30,1,1,1,'CentOS 6 SELinux Allow FTP Directory Change','setsebool -P ftp_home_dir=1',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (31,1,1,1,'CentOS Google Cloud SDK Working With Python 2.7','# get pip2.7\\r\\nwget https://bootstrap.pypa.io/get-pip.py\\r\\npython2.7 get-pip.py\\r\\n\\r\\n# install the gcloud module\\r\\npip2.7 install google_compute_engine\\r\\n\\r\\n# add to .bashrc\\r\\nexport CLOUDSDK_PYTHON=/usr/local/bin/python2.7',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (33,1,1,1,'Convert Bare Git Repo to Normal Repo','mkdir .git\\r\\nmv branches/ config description HEAD hooks/ info/ objects/ refs/ .git\\r\\ngit config --local --bool core.bare false\\r\\ngit checkout master\\r\\ngit reset --hard',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (34,1,1,1,'Linux Primitive UDP Hole Punching','# from machine1 (1.2.3.4)\\r\\n# punch a hole in the firewall\\r\\nhping2 -c 1 -2 -s 14141 -p 53 5.6.7.8\\r\\n\\r\\n# from machine1 (firewalled)\\r\\n# listen for connections on 1.2.3.4:14141\\r\\nnc -u -l -p 14141\\r\\n\\r\\n# from machine2 (5.6.7.8)\\r\\n# send a message to 1.2.3.4:14141 from 5.6.7.8:53\\r\\necho \\'test\\' | nc -p 53 -u 1.2.3.4 14141',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (35,1,1,1,'Install Python 3.4.5 on CentOS 6/7','sudo yum groupinstall -y \\'development tools\\'\\r\\nwget http://python.org/ftp/python/3.4.5/Python-3.4.5.tar.xz\\r\\nxz -d Python-3.4.5.tar.xz\\r\\ntar -xvf Python-3.4.5.tar\\r\\nrm -f Python-3.4.5.tar\\r\\ncd Python-3.4.5\\r\\n./configure\\r\\nmake && make altinstall\\r\\ncd ..',now());\ninsert into cli_scripts (cli_script_id, user_id, is_public, is_safe, title, content, created_at) values (36,1,1,1,'Install Latest Docker & Compose on CentOS 6/7','# Docker\\r\\nsudo yum install -y yum-utils device-mapper-persistent-data lvm2\\r\\nsudo yum-config-manager -y --add-repo https://download.docker.com/linux/centos/docker-ce.repo\\r\\nsudo yum install -y docker-ce\\r\\nsudo usermod -aG docker $(whoami)\\r\\nsudo systemctl enable docker.service\\r\\nsudo systemctl start docker.service\\r\\n\\r\\n# Docker Compose\\r\\nsudo yum install -y epel-release\\r\\nsudo yum install -y python-pip\\r\\nsudo pip install docker-compose\\r\\nsudo yum upgrade -y python*',now());\n"
  },
  {
    "path": "var/tmp/stats.sql",
    "content": "select\n    user,\n    count(*) as messages\nfrom discord_chat_messages\nwhere\n    created_at > '2021-07-29 00:00:00' and\n    channel not in (\n        'team-room',\n        'hero-room',\n        'oof-topic',\n        'command-center',\n        'moderator-report',\n        'gaming',\n        'music',\n        'bot-playground'\n    ) and\n    discord_id in (\n        '252862670842232832',\n        '431464792075665418',\n        '98488345952256000',\n        '460172222489952266',\n        '473160828502409217',\n        '274618567977205761',\n        '187677490452496394',\n        '449274804651032577',\n        '342099904056786945',\n        '186436642356068352',\n        '245697230982479872',\n        '381632413010231309',\n        '173679469872152576'\n    )\ngroup by discord_id\norder by messages desc;\n\n\nselect\n    user,\n    count(*) as messages\nfrom discord_chat_messages\nwhere\n    created_at > '2021-07-29 00:00:00' and\n    channel not in (\n        'team-room',\n        'hero-room',\n        'oof-topic',\n        'command-center',\n        'moderator-report',\n        'gaming',\n        'music',\n        'bot-playground'\n    ) and\n    discord_id in (\n        '319509382889209866',\n        '681375864042160128',\n        '222005750598205440',\n        '243412893234757632',\n        '532835388448833556',\n        '271357207180738563',\n        '406634590325964801',\n        '276380118761340928',\n        '563228793704022038',\n        '496790880548814858',\n        '158250066417549312',\n        '266140088138858496',\n        '710952300209766410',\n        '197774061315686400',\n        '536269399783505950'\n    )\ngroup by discord_id\norder by messages desc;\n"
  },
  {
    "path": "var/tmp/vids.sql",
    "content": "insert into video_requests values (default, 1, 'General - Design Patterns', now());\ninsert into video_requests values (default, 1, 'Python - Twitter Bot (posts photos)', now());\ninsert into video_requests values (default, 1, 'Python - GUI basics', now());\ninsert into video_requests values (default, 1, 'General - Reverse Engineering', now());\ninsert into video_requests values (default, 1, 'Python - Image Recognition', now());\ninsert into video_requests values (default, 1, 'Challenge - Space Invaders game challenge', now());\ninsert into video_requests values (default, 1, 'Shell - Makefiles', now());\ninsert into video_requests values (default, 1, 'General - Hashing vs Encryption', now());\ninsert into video_requests values (default, 1, 'Python - pandas', now());\ninsert into video_requests values (default, 1, 'General - Google Sheets API', now());\ninsert into video_requests values (default, 1, 'Shell - awk basics', now());\ninsert into video_requests values (default, 1, 'General - Staff Hangman Bots (Overview)', now());\ninsert into video_requests values (default, 1, 'Python - Implementing Regex into code', now());\ninsert into video_requests values (default, 1, 'General - Bitwise operators', now());\ninsert into video_requests values (default, 1, 'Python - Object Oriented Programming', now());\ninsert into video_requests values (default, 1, 'Python - AES Implementation', now());\ninsert into video_requests values (default, 1, 'Python - JSON and XML', now());\ninsert into video_requests values (default, 1, 'node.js - Await/Async', now());\ninsert into video_requests values (default, 1, 'Python - Simple Rest API', now());\ninsert into video_requests values (default, 1, 'Python - Intermediate Series', now());\ninsert into video_requests values (default, 1, 'C - Combining and compiling multiple C source files together', now());\ninsert into video_requests values (default, 1, 'C - Signal handling', now());\ninsert into video_requests values (default, 1, 'Shell - sed basics', now());\ninsert into video_requests values (default, 1, 'Shell - grep basics', now());\ninsert into video_requests values (default, 1, 'Python - Map, Filter, Reduce', now());\ninsert into video_requests values (default, 1, 'Python - How to use sqlite 3', now());\ninsert into video_requests values (default, 1, 'Linux - Beginner Commands', now());\ninsert into video_requests values (default, 1, 'Any - Discord Webhooks', now());\ninsert into video_requests values (default, 1, 'General - REST API', now());\ninsert into video_requests values (default, 1, 'Career - Interview Questions', now());\ninsert into video_requests values (default, 1, 'General - XML', now());\ninsert into video_requests values (default, 1, 'General - Bash', now());\ninsert into video_requests values (default, 1, 'Python - Sound Analyzer', now());\n"
  }
]