See CodeChum hidden test cases

See hidden test cases as if they are not hidden in codechum after you press submit

目前為 2022-09-28 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         See CodeChum hidden test cases
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  See hidden test cases as if they are not hidden in codechum after you press submit
// @author       CIT Hackerz
// @match        https://citu.codechum.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=codechum.com
// @grant        none
// ==/UserScript==

const testCaseEndpoint = new RegExp('answers-v4\/[0-9]+\/executev2', 'g');

// Stylings
const style_testCaseContent = `display: grid; grid-row-gap: 16px; grid-template-column: minmax(0, 1fr); margin: 16px 0 8px;`;
const style_testCaseContent_title = `margin: 8px 0 12px;`;
const style_Text_n = `color: #b0b9bf;`;
const style_Text_heading = `font-family: Monsterrat,sans-serif; font-size: 1rem; line-height: 1.25; font-weight: 700; font-style: normal;`
const style_pre = `color: rgb(204, 204, 204); border-radius: 8px; background: rgb(45, 45, 45); font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; overflow-wrap: normal; line-height: 1.5; tab-size: 4; hyphens: none; padding: 1em; margin: 0.5em 0px; overflow: auto;`;
const style_Code_sm = `background-color: #2d3845 !important;`
const style_code_el = `color: rgb(204, 204, 204); font-size: 14px; background: none; font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; overflow-wrap: normal; line-height: 1.5; tab-size: 4; hyphens: none;`;

// Test Case template
const testCaseDiv = document.createElement("div");
testCaseDiv.innerHTML = `
<div style="${style_testCaseContent}">
    <div>
        <h6 style="${style_testCaseContent_title}${style_Text_n}${style_Text_heading}">
            Expected Output
        </h6>
        <div>
            <pre style='${style_pre}${style_Code_sm}'><code style='${style_code_el}'>
                    put test cases in here
                </code></pre>
        </div>
    </div>
</div>
`;

function event_displayHiddenCaseOnClick(e){
    // if next sibling (test case container) is hidden, then show, else hide
    const testCase = this.nextElementSibling;

    if(testCase.style.display != "block"){
        // show
        testCase.style.display = "block";
    }else{
        // hide
        testCase.style.display = "none";
    }

    console.log(testCase.style.display);
}

function displayCase(cases){

    // fucking obfuscation
    let testCaseCont = Array.from(document.querySelectorAll('div')).filter(e => e.classList.length > 0).filter(e => Array.from(e.classList).some(cl => cl.includes("styles_InputOutput_testCases")));

    // if there is a constraint, then the test case content is the second child
    testCaseCont = ((testCaseCont.length > 1) ? testCaseCont[1] : testCaseCont[0]).children[1];

    testCaseCont.children.forEach( (div, i) => {
        if(!div.children[0].disabled) return; // only modify hidden test cases

        const caseCont = testCaseDiv.cloneNode(true);
        caseCont.style.display = "none";

        caseCont.querySelector('code').innerHTML = cases[i].trim();

        // if div is not yet marked, add an event listener to the button
        if(div.dataset.marked != "true"){
            div.children[0].disabled = false;
            div.children[0].addEventListener("click", event_displayHiddenCaseOnClick);
            div.children[0].cursor = "pointer";
        }

        // set the div as marked
        div.dataset.marked = "true";

        div.append(caseCont);
    });
}

function saveCase(arg){
    let saved = sessionStorage.getItem("saved_test_cases") || [
        {
            problem: arg.id,
            cases: arg.cases
        }
    ];

    if(typeof saved == "string"){
        saved = JSON.parse(saved);
        saved.push({
           problem: arg.id,
            cases: arg.cases
        });
    }

    sessionStorage.setItem("saved_test_cases", JSON.stringify(saved));
}

function receiveCases(arg){
    let res;

    try {
        res = JSON.parse(arg.response);
    }catch (err){
        return;
    }

    const testCase = {
        id: res.id,
        answer_id: res.answer_id,
        cases: res.test_case_statuses.map(e => e.test_case.output)
    }

    displayCase(testCase.cases);
    //saveCase(testCase);
}

(function() {
    'use strict';

    // Modify open and send requests

    var open = window.XMLHttpRequest.prototype.open,
        send = window.XMLHttpRequest.prototype.send;

    function openReplacement(method, url, async, user, password) {
        this._url = url;
        return open.apply(this, arguments);
    }

    function sendReplacement(data) {
        if(this.onreadystatechange) {
            this._onreadystatechange = this.onreadystatechange;
        }

        // if you want to modify send requests

        this.onreadystatechange = onReadyStateChangeReplacement;
        return send.apply(this, arguments);
    }

    function onReadyStateChangeReplacement() {

        // modify here received requests
        if(testCaseEndpoint.test(this._url)) receiveCases(this);

        if(this._onreadystatechange) {
            return this._onreadystatechange.apply(this, arguments);
        }
    }

    window.XMLHttpRequest.prototype.open = openReplacement;
    window.XMLHttpRequest.prototype.send = sendReplacement;

    var request = new XMLHttpRequest();
    request.open('GET', '.', true);
    request.send();

})();