Ex124OJ

Extend 124OJ!

2022-12-16 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Ex124OJ
// @namespace    http://tampermonkey.net/
// @version      0.10.5
// @description  Extend 124OJ!
// @author       Sukwants
// @license      MIT
// @match        http://124.221.194.184
// @match        http://124.221.194.184/*
// @icon         https://www.imageoss.com/images/2022/11/29/ex124OJba563861978a769d.png
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @grant        GM_listValues
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @connect      ex124oj.netlify.app
// ==/UserScript==


const Version = '0.10.5';

const HomepageRegExp = /^http:\/\/124.221.194.184(\/){0,1}(\?.*){0,1}$/;
function isHomepage() {
    return HomepageRegExp.test(window.location.href);
}
const submissionRegExp = /^http:\/\/124.221.194.184\/submission\/\d{1,}/;
function isSubmission() {
    return submissionRegExp.test(window.location.href);
}
const ProblemRegExp = /^http:\/\/124.221.194.184.*\/problem\/(\d{1,})(\?.*){0,1}$/;
function isProblem() {
    return ProblemRegExp.test(window.location.href);
}
const UserProfileRegExp = /^http:\/\/124.221.194.184\/user\/profile\/.{1,}/;
function isUserProfile() {
    return UserProfileRegExp.test(window.location.href);
}
const BlogRegExp = /^http:\/\/124.221.194.184\/blog\/.{1,}/;
function isBlog() {
    return BlogRegExp.test(window.location.href);
}

var BackgroundImage;
var SiteIconImage;
var SiteIconSmallImage;
var Academic;
function resetVariables() {
    BackgroundImage = GM_getValue('BackgroundImage') != undefined ? GM_getValue('BackgroundImage') : '';
    SiteIconImage = GM_getValue('SiteIconImage') != undefined ? GM_getValue('SiteIconImage') : 'https://www.imageoss.com/images/2022/11/29/ex124OJba563861978a769d.png';
    SiteIconSmallImage = GM_getValue('SiteIconSmallImage') != undefined ? GM_getValue('SiteIconSmallImage') : 'https://www.imageoss.com/images/2022/12/13/icon1ca65ac1e49f8ec3c.png';
    Academic = GM_getValue('Academic') != undefined ? GM_getValue('Academic') : false;
}
resetVariables();

var NameColorList = GM_getValue('NameColorList') != undefined ? GM_getValue('NameColorList') : {};
var CCFBadgeList = GM_getValue('CCFBadgeList') != undefined ? GM_getValue('CCFBadgeList') : {};
var TagBadgeList = GM_getValue('TagBadgeList') != undefined ? GM_getValue('TagBadgeList') : {};
GM_xmlhttpRequest({
    method: "GET",
    url: "https://ex124oj.netlify.app/public/variables.json",
    onload: function(data) {
        var variables = JSON.parse(data.responseText);
        NameColorList = variables.NameColorList;
        GM_setValue('NameColorList', NameColorList);
        CCFBadgeList = variables.CCFBadgeList;
        GM_setValue('CCFBadgeList', CCFBadgeList);
        TagBadgeList = variables.TagBadgeList;
        GM_setValue('TagBadgeList', TagBadgeList);
        FunctionsWithUniversalVariables();
    }
});

(function() {
    'use strict';
    Settings();
    FontAwesome();
    Background();
    changeIcon();
    DiscussionCard();
    CodeBlock();
    TableStyle();
    RandomProblem();
    if (isHomepage()) exAnnouncements();
    if (isSubmission()) SubmissionCard();
    if (isProblem()) downloadData();
    if (isUserProfile() || isBlog()) changeGravatarURL();
    FunctionsWithUniversalVariables();
})();

function FunctionsWithUniversalVariables() {
    clearNameStyle();
    NameColor();
    NameBadge();
}

function Settings() {
    GM_addStyle('\
.settings-overlay {\
    position: fixed;\
    height: 100%;\
    width: 100%;\
    transition: visibility 0.4s, background 0.4s;\
    top: 0;\
    left: 0;\
    visibility: hidden;\
    z-index: 229;\
}\
.settings-popup-active .settings-overlay {\
    background: rgb(0,0,0,.3);\
    visibility: visible;\
}\
.settings-popup {\
    width: 60%;\
    position: relative;\
    transform: translate(-50%, -50%);\
    top: 50%;\
    left: 50%;\
    visibility: hidden;\
    border-radius: .5rem;\
    padding: 20px 20px;\
}\
.settings-popup-active .settings-overlay .settings-popup {\
    background: #ffffff;\
    visibility: visible;\
}\
.settings-popup .row {\
    padding: 0 30px 30px;\
}\
.settings-titlebar {\
    padding: 10px 20px 30px 20px !important;\
}\
.settings-titlebar h4 {\
    position: relative;\
    top: 50%;\
    left: 0;\
    transform: translate(0, -50%);\
}\
.settings-footerbar {\
    height: 60px;\
    padding: 20px 20px;\
}\
');
    var HomepageEntrance = document.createElement('li');
    document.getElementsByClassName('container')[0].children[0].children[0].children[0].before(HomepageEntrance);
    HomepageEntrance.setAttribute('class', 'nav-item');
    HomepageEntrance.innerHTML = '<span style="padding: 0.5rem 1rem; cursor:pointer"><span style="background-color: #28adca;padding:0.2em 0.6em;border-radius: 1em;color:#fff;font-size: 0.7em;font-weight:bold;display:inline-block;position: relative;top: 50%;transform: translate(0,-50%);">Ex124OJ</span></span>';
    HomepageEntrance.onclick = function() {
        document.body.setAttribute('class', 'settings-popup-active');
    }
    var SettingsOverlay = document.createElement('div');
    document.body.children[0].before(SettingsOverlay);
    SettingsOverlay.setAttribute('class', 'settings-overlay');
    var SettingsPopup = document.createElement('div');
    SettingsOverlay.appendChild(SettingsPopup);
    SettingsPopup.setAttribute('class', 'settings-popup');
    var SettingsTitlebar = document.createElement('div');
    SettingsPopup.appendChild(SettingsTitlebar);
    SettingsTitlebar.setAttribute('class', 'row settings-titlebar');
    SettingsTitlebar.innerHTML = '<h3 style="width: 100%;"><img src="https://ex124oj.netlify.app/images/icon.png" style="height:3.5rem;width:3.5rem;margin-right:10px"><span style="line-height: 3.5rem;vertical-align: middle"> Ex124OJ 控制面板</span> <span style="padding: 0.5rem 1rem;vertical-align: middle;cursor: pointer" onclick="window.open(\'https://ex124oj.netlify.app/\');"><span style="background-color: #28adca;padding:0.2em 0.6em;border-radius: 1em;color:#fff;font-size: 0.7em;font-weight:bold;display:inline-block;">Ex124OJ</span></span><small style="color:#7f7f7f">' + Version + '</small></h3>';
    var SettingsCloseButton = document.createElement('span');
    SettingsPopup.appendChild(SettingsCloseButton);
    SettingsCloseButton.setAttribute('style', 'position: fixed;right: 20px;top:20px;cursor: pointer');
    SettingsCloseButton.setAttribute('onclick', 'document.body.setAttribute(\'class\', \'\');');
    SettingsCloseButton.innerHTML = '<h4><i class="fa fa-xmark"></i></h4>';

    var background = document.createElement('div');
    SettingsPopup.appendChild(background);
    background.setAttribute('class', 'row');
    var backgroundImageLabel = document.createElement('strong');
    background.appendChild(backgroundImageLabel);
    backgroundImageLabel.setAttribute('style', 'font-size: 1.25em');
    backgroundImageLabel.innerHTML = '背景图片&emsp;&emsp;&emsp;&emsp;';
    var backgroundImageInput = document.createElement('input');
    background.appendChild(backgroundImageInput);
    backgroundImageInput.setAttribute('style', 'flex-grow: 1; height: 2em; width: initial');
    backgroundImageInput.setAttribute('class', 'form-control');

    var siteIcon = document.createElement('div');
    SettingsPopup.appendChild(siteIcon);
    siteIcon.setAttribute('class', 'row');
    var siteIconImageLabel = document.createElement('strong');
    siteIcon.appendChild(siteIconImageLabel);
    siteIconImageLabel.setAttribute('style', 'font-size: 1.25em');
    siteIconImageLabel.innerHTML = '网站图标&emsp;&emsp;&emsp;&emsp;';
    var siteIconImageInput = document.createElement('input');
    siteIcon.appendChild(siteIconImageInput);
    siteIconImageInput.setAttribute('style', 'flex-grow: 1; height: 2em; width: initial');
    siteIconImageInput.setAttribute('class', 'form-control');

    var siteIconSmall = document.createElement('div');
    SettingsPopup.appendChild(siteIconSmall);
    siteIconSmall.setAttribute('class', 'row');
    var siteIconSmallImageLabel = document.createElement('strong');
    siteIconSmall.appendChild(siteIconSmallImageLabel);
    siteIconSmallImageLabel.setAttribute('style', 'font-size: 1.25em');
    siteIconSmallImageLabel.innerHTML = '网站图标(小)&emsp;';
    var siteIconSmallImageInput = document.createElement('input');
    siteIconSmall.appendChild(siteIconSmallImageInput);
    siteIconSmallImageInput.setAttribute('style', 'flex-grow: 1; height: 2em; width: initial');
    siteIconSmallImageInput.setAttribute('class', 'form-control');

    var academic = document.createElement('div');
    SettingsPopup.appendChild(academic);
    academic.setAttribute('class', 'row');
    academic.setAttribute('style', 'line-height: 2.5em;vertical-align: middle');
    var academicLabel = document.createElement('strong');
    academic.appendChild(academicLabel);
    academicLabel.setAttribute('style', 'font-size: 1.25em');
    academicLabel.innerHTML = '学术模式&emsp;&emsp;&emsp;&emsp;';
    var academicOff = document.createElement('div');
    academic.appendChild(academicOff);
    academicOff.innerHTML = '<input type="radio" id="AcademicOff"> 关闭&emsp;';
    var academicOn = document.createElement('div');
    academic.appendChild(academicOn);
    academicOn.innerHTML = '<input type="radio" id="AcademicOn"> 开启&emsp;';
    document.getElementById('AcademicOff').onclick = function() {
        document.getElementById('AcademicOn').checked = false;
    }
    document.getElementById('AcademicOn').onclick = function() {
        document.getElementById('AcademicOff').checked = false;
    }

    function resetModified() {
        backgroundImageInput.value = BackgroundImage;
        siteIconImageInput.value = SiteIconImage;
        siteIconSmallImageInput.value = SiteIconSmallImage;
        if (Academic != true) {
            document.getElementById('AcademicOff').checked = true;
            document.getElementById('AcademicOn').checked = false;
        }
        else {
            document.getElementById('AcademicOff').checked = false;
            document.getElementById('AcademicOn').checked = true;
        }
    }
    resetModified();

    var FooterRow = document.createElement('div');
    FooterRow.setAttribute('class', 'settings-footerbar');
    SettingsPopup.appendChild(FooterRow);
    var Ok = document.createElement('button');
    FooterRow.appendChild(Ok);
    Ok.setAttribute('class', 'btn btn-search btn-outline-primary float-right');
    Ok.innerHTML = '保存';
    Ok.onclick = function() {
        GM_setValue('BackgroundImage', backgroundImageInput.value);
        GM_setValue('SiteIconImage', siteIconImageInput.value);
        GM_setValue('SiteIconSmallImage', siteIconSmallImageInput.value);
        GM_setValue('Academic', document.getElementById('AcademicOn').checked);
        resetVariables();
        window.location.href = window.location.href;
    };
    var Clear = document.createElement('button');
    FooterRow.appendChild(Clear);
    Clear.setAttribute('class', 'btn btn-search btn-outline-primary float-right');
    Clear.innerHTML = '恢复默认';
    Clear.onclick = function() {
        var values = GM_listValues();
        for (var value in values) {
            GM_deleteValue(values[value]);
        }
        resetVariables();
        resetModified();
        window.location.href = window.location.href;
    }
}

function FontAwesome() {
    var fa = document.createElement('link');
    fa.setAttribute('href', 'https://cdn.bootcdn.net/ajax/libs/font-awesome/6.2.1/css/fontawesome.css');
    fa.setAttribute('rel', 'stylesheet');
    document.head.appendChild(fa);
    var fab = document.createElement('link');
    fab.setAttribute('href', 'https://cdn.bootcdn.net/ajax/libs/font-awesome/6.2.1/css/brands.css');
    fab.setAttribute('rel', 'stylesheet');
    document.head.appendChild(fab);
    var fas = document.createElement('link');
    fas.setAttribute('href', 'https://cdn.bootcdn.net/ajax/libs/font-awesome/6.2.1/css/solid.css');
    fas.setAttribute('rel', 'stylesheet');
    document.head.appendChild(fas);
}

function Background() {
    if (BackgroundImage) {
        document.getElementsByClassName('navbar-brand')[0].innerHTML = '<img src="http://124.221.194.184/images/logo_small.png" alt="Logo" class="img-rounded" style="width:39px; height:39px;">';
        document.getElementsByClassName('container')[0].children[0].children[1].innerHTML = document.getElementsByClassName('container')[0].children[0].children[1].innerHTML.match(/(.*> ){0,1}(.*)/)[2];
        GM_addStyle('\
body {\
background: url("' + BackgroundImage + '");\
background-repeat: no-repeat;\
background-attachment: fixed;\
background-position: 50% 50%;\
background-size: cover;\
}\
.uoj-content {\
background-color: #fff;\
margin: 16px -16px;\
padding: 16px 16px;\
opacity: 0.85;\
border-radius: 8px;\
}\
.navbar {\
margin: 16px -16px;\
padding: 8px 16px;\
opacity: 0.85;\
border-radius: 8px;\
}\
.giscus {\
opacity: 0.85;\
}');
    }
}

function getIcon() {
    if (SiteIconImage) return SiteIconImage;
    else return '/images/logo.png';
}
function getIconSmall() {
    if (SiteIconSmallImage) return SiteIconSmallImage;
    else return getIcon();
}
function changeIcon() {
    const LogoURLRegExp = /^.*\/images\/logo(_small){0,1}.png$/;
    var Links = document.getElementsByTagName('link');
    for (var link in Links) {
        if (Links[link] && Links[link].nodeType && Links[link].getAttribute('rel') == 'shortcut icon') {
            Links[link].setAttribute('href', getIconSmall());
        }
    }
    var Icons = document.getElementsByTagName('img');
    for (var icon in Icons) {
        if (Icons[icon] && Icons[icon].nodeType && LogoURLRegExp.test(Icons[icon].getAttribute('src'))) {
            if (!Icons[icon].getAttribute('style')) {
                Icons[icon].setAttribute('src', getIcon());
                Icons[icon].setAttribute('style', 'width:100%;height:auto;object-fit:cover');
            }
            else {
                Icons[icon].setAttribute('src', getIconSmall());
            }
        }
    }
}

function exAnnouncements() {
    const PostsExp = /^[\s\S]*<div id="archives">([\s\S]*)<script>([\s\S]*?)<\/script>([\s\S]*?)<\/div>\s*?<footer id="footer">[\s\S]*$/;
    const WrittenByExp = /^by (.*)$/;
    const DateTimeExp = /^(.*?) .*$/;
    if (document.getElementsByClassName('uoj-content')[0].children[0].children[0].children[0]) {
        GM_xmlhttpRequest({
            method: "GET",
            url: "https://ex124oj.netlify.app/categories/announcements/",
            onload: function(data) {
                var Announcements = document.getElementsByClassName('uoj-content')[0].children[0].children[0].children[0].children[0].children[0];
                Announcements.children[0].children[0].innerHTML = '<th style="width:30%">公告</th><th style="width:10%"></th><th style="width:10%"></th><th style="width:30%">Ex 公告</th><th style="width:10%"></th><th style="width:10%"></th>';
                var trs = Announcements.children[1].getElementsByTagName('tr');
                for (var tr = 0; tr < trs.length - 1; ++tr) {
                    if (trs[tr].innerHTML) {
                        trs[tr].innerHTML = (trs[tr].children.length > 2 ? trs[tr].innerHTML : '<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>') + '<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>';
                        if (WrittenByExp.test(trs[tr].children[1] && trs[tr].children[1].innerHTML)) {
                            trs[tr].children[1].innerHTML = trs[tr].children[1].innerHTML.match(WrittenByExp)[1];
                        }
                        if (DateTimeExp.test(trs[tr].children[2] && trs[tr].children[2].innerHTML)) {
                            trs[tr].children[2].innerHTML = '<small>' + trs[tr].children[2].textContent.match(DateTimeExp)[1] + '</small>';
                        }
                    }
                }
                Announcements.children[1].children[Announcements.children[1].children.length - 1].innerHTML = '<td class="text-right" colspan="3"><a href="/announcements">所有公告……</a></td><td class="text-right" colspan="3"><a href="https://ex124oj.netlify.app/categories/announcements/">所有公告……</a></td>';
                var Posts = document.createElement('div');
                Posts.innerHTML = data.responseText.match(PostsExp)[1];
                for (var i = 0; i < Posts.children.length && i < 5; ++i) {
                    Announcements.children[1].children[i].children[3].innerHTML = '<a href="https://ex124oj.netlify.app' + Posts.children[i].children[0].children[0].children[1].getAttribute('href') + '">' + Posts.children[i].children[0].children[0].children[1].children[0].innerHTML.match(/^\s*(.*?)\s*$/)[1] + '</a>';
                    Announcements.children[1].children[i].children[4].innerHTML = '<a class="uoj-username" href="https://ex124oj.netlify.app" style="color:rgb(40,173,202)">Ex124OJ</a>';
                    var Date = Posts.children[i].children[0].children[0].children[0].innerHTML.match(/^(\d*)\/(\d*)\/(\d*)$/);
                    if (Date[2].length < 2) Date[2] = '0' + Date[2];
                    if (Date[3].length < 2) Date[3] = '0' + Date[3];
                    Announcements.children[1].children[i].children[5].innerHTML = '<small>' + Date[1] + '-' + Date[2] + '-' + Date[3] + '</small>'
                }
            }
        });
    }
}

function RandomProblem() {
    var SearchBox = document.getElementById('form-search-problem')
    if (SearchBox) {
        var RandomButton = document.createElement('div');
        RandomButton.setAttribute('class', 'input-group-append');
        RandomButton.innerHTML = '<button class="btn btn-search btn-outline-primary" onclick="randomProblem();">随机跳题</button>';
        var RandomScript = document.createElement('script');
        RandomScript.innerHTML = '\
var randomProblemId, randomProblemResult;\
function randomProblem() {\
    randomProblemId = Math.ceil(Math.random() * 3000);\
    randomProblemResult = ($.get(\'/problem/\' + randomProblemId));\
    turntoProblem();\
}\
function turntoProblem() {\
    console.log(randomProblemResult.status);\
    if (randomProblemResult.status) {\
        if (randomProblemResult.status == 200) {\
            window.location.href = \'http://124.221.194.184/problem/\' + randomProblemId;\
        }\
        else {\
            randomProblem();\
        }\
    }\
    else {\
        setTimeout(turntoProblem, 10);\
    }\
}';
        SearchBox.after(RandomButton);
        RandomButton.after(RandomScript);
    }
}

function DiscussionCard() {
    var discrd = document.createElement('div');
    discrd.setAttribute('class', 'giscus');
    document.getElementsByClassName('uoj-footer')[0].before(discrd);
    var script = document.createElement('script');
    script.setAttribute('src', 'https://giscus.app/client.js');
    script.setAttribute('data-repo', 'Sukwants/Discuss124OJ');
    script.setAttribute('data-repo-id', 'R_kgDOImiZLA');
    script.setAttribute('data-category', 'Ideas');
    script.setAttribute('data-category-id', 'DIC_kwDOImiZLM4CTCIj');
    script.setAttribute('data-mapping', 'pathname');
    script.setAttribute('data-strict', '0');
    script.setAttribute('data-reactions-enabled', '1');
    script.setAttribute('data-emit-metadata', '0');
    script.setAttribute('data-input-position', 'top');
    script.setAttribute('data-theme', 'preferred_color_scheme');
    script.setAttribute('data-lang', 'zh-CN');
    script.setAttribute('crossorigin', 'anonymous');
    script.setAttribute('async', '');
    document.getElementsByTagName('body')[0].appendChild(script);
    GM_addStyle('\
.giscus {\
    display: ' + (Academic == true ? 'none' : 'unset') + ';\
}\
.giscus-frame {\
    margin-top: 20px;\
}');
}

function CodeBlock() {
    const ManageStatementExp = /^.*\/manage\/statement(\?.*){0,1}$/
    GM_addStyle('\
@import url(https://cdn.jsdelivr.net/npm/[email protected]/distr/fira_code.css);\
code {\
    font-family: "Fira Code";\
}\
code.sh_cpp>span {\
    font-style: normal !important;\
    font-weight: 400 !important;\
}\
code.sh_cpp>span.sh_preproc,\
code.sh_cpp>span.sh_keyword,\
code.sh_cpp>span.sh_type {\
    color: #8959a8;\
}\
code.sh_cpp>span.sh_string {\
    color: #718c00;\
}\
code.sh_cpp>span.sh_cbracket {\
    color: #4d4d4c;\
}\
code.sh_cpp>span.sh_symbol {\
    color: #3e999f;\
}\
code.sh_cpp>span.sh_number {\
    color: #f5871f;\
}\
code.sh_cpp>span.sh_function {\
    color: #4271ae;\
}\
code.sh_cpp>span.sh_comment {\
    color: #8e908c;\
}\
.copybutton {\
    float: right;\
    background-color: rgb(0,0,0,.1);\
    padding: .25em .625em;\
    border: 0 solid transparent;\
    border-radius: .28571429rem;\
}\
.copybutton:hover {\
    background-color: rgb(0,0,0,.2);\
}\
.copybutton:focus {\
    background-color: rgb(0,0,0,.2);\
    outline: none;\
}');
    if (!ManageStatementExp.test(window.location.href)) {
        setTimeout(function(){
            var CodeBlocks = document.getElementsByTagName('pre');
            for (var cb in CodeBlocks) {
                if (CodeBlocks[cb] && CodeBlocks[cb].nodeType) {
                    var Content = CodeBlocks[cb].textContent;
                    var InputId = Math.round(Math.random() * 998244353);
                    var ButtonId = Math.round(Math.random() * 998244353);
                    CodeBlocks[cb].innerHTML = '<button class="copybutton" id = "' + ButtonId + '" onclick="\
var ib = document.getElementById(\'' + InputId + '\');\
ib.setAttribute(\'style\', \'display:initial\');\
ib.value = \'' + Content.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/'/g, '\\&#39;').replace(/"/g, '&#34;') + '\';\
ib.select();\
document.execCommand(\'copy\');\
ib.setAttribute(\'style\', \'display:none\');\
var ic = document.getElementById(\'' + ButtonId + '\');\
ic.innerHTML = \'已复制\';\
setTimeout(function() { ic.innerHTML = \'复制\'; }, 500);">复制</button>' + CodeBlocks[cb].innerHTML;
                    var InputBox = document.createElement('textarea');
                    InputBox.setAttribute('id', InputId);
                    InputBox.setAttribute('style', 'display:none');
                    CodeBlocks[cb].appendChild(InputBox);
                }
            }

        }, 30);
    }
}

function TableStyle() {
    var Tables = document.getElementsByTagName('table');
    for (var table in Tables) {
        if (Tables[table].nodeType && Tables[table].parentNode.getAttribute('class') != 'legend' && !Tables[table].classList.length) {
            Tables[table].classList.add('table', 'table-bordered');
        }
    }
    var ths = document.getElementsByTagName('th');
    for (var th in ths) {
        if (ths[th].nodeType && ths[th].getAttribute('align')) {
            ths[th].setAttribute('style', 'text-align:' + ths[th].getAttribute('align'));
        }
    }
}

function SubmissionCard() {
    setTimeout(function() {
        var Content = document.getElementsByClassName('uoj-content')[0];
        if (Content.childElementCount == 3) {
            var Table = Content.children[0];
            var TabList = document.createElement('ul');
            TabList.setAttribute('class', 'nav nav-tabs');
            TabList.setAttribute('role', 'tablist');
            TabList.innerHTML = '<li class="nav-item"><a class="nav-link active" href="#test-cases" role="tab" data-toggle="tab" aria-selected="true"><span class="glyphicon glyphicon-check"></span> 测试点信息</a></li><li class="nav-item"><a class="nav-link" href="#source" role="tab" data-toggle="tab" aria-selected="false"><span class="glyphicon glyphicon-file"></span> 源代码</a></li>';
            var TabContent = document.createElement('div');
            TabContent.setAttribute('class', 'tab-content');
            TabContent.innerHTML = '<div class="tab-pane card active" id="test-cases"><div class="card-body">' + Content.children[2].children[1].innerHTML + '</div></div><div class="tab-pane card" id="source"><div class="card-body">' + Content.children[1].children[1].innerHTML + '</div></div>';
            Content.innerHTML = "";
            Content.appendChild(Table);
            Content.appendChild(TabList);
            Content.appendChild(TabContent);
        }
    }, 50);
}

function downloadData() {
    var DownloadTag = document.createElement('a');
    DownloadTag.setAttribute('role', 'button');
    DownloadTag.setAttribute('class', 'btn btn-primary float-right');
    DownloadTag.setAttribute('href', '/download.php?type=problem&id=' + window.location.href.match(ProblemRegExp)[1]);
    DownloadTag.setAttribute('target', '_blank');
    DownloadTag.innerHTML = '<span class="glyphicon glyphicon-download-alt"></span> 下载数据';
    document.getElementsByClassName("btn btn-info float-right")[0].after(DownloadTag);
}

function changeGravatarURL() {
    const GravatarURLRegExp = /\/\/cn.gravatar.com\/avatar\/(.*)$/;
    var Gravatar = document.getElementsByClassName('img-thumbnail')[0];
    if (Gravatar && Gravatar.nodeType){
        console.log(Gravatar);
        Gravatar.setAttribute('src', '//gravatar.loli.net/avatar/' + Gravatar.getAttribute('src').match(GravatarURLRegExp)[1]);
    }
    var Gravatars = document.getElementsByClassName('img-rounded');
    for (var gravatar in Gravatars) {
        if (Gravatars[gravatar] && Gravatars[gravatar].nodeType && GravatarURLRegExp.test(Gravatars[gravatar].getAttribute('src'))) {
            Gravatars[gravatar].setAttribute('src', '//gravatar.loli.net/avatar/' + Gravatars[gravatar].getAttribute('src').match(GravatarURLRegExp)[1]);
        }
    }
}

function clearNameStyle() {
    const NameExp = /^(.{1,}?)( .*)*$/;
    var Names = document.getElementsByClassName('uoj-username');
    for (var i in Names) {
        if (!Names[i].innerHTML) continue;
        Names[i].innerHTML = Names[i].textContent.match(NameExp)[1];
    }
    var Honors = document.getElementsByClassName('uoj-honor');
    for (var j in Honors) {
        if (!Honors[j].innerHTML) continue;
        Honors[j].innerHTML = Honors[j].textContent.match(NameExp)[1];
    }
}

function NameColor() {
    var Names = document.getElementsByClassName('uoj-username');
    var NeedsRepeat = false;
    for (var i in Names) {
        if (Names[i].innerHTML && NameColorList[Names[i].innerHTML]) {
            Names[i].style = 'color:' + NameColorList[Names[i].innerHTML][0];
            var resN = '';
            for (var charN = 1; charN < NameColorList[Names[i].innerHTML].length; ++charN) {
                resN = resN + '<font style="color:' + NameColorList[Names[i].innerHTML][charN] + '">' + Names[i].innerHTML.substring(charN - 1, charN) + '</font>';
            }
            Names[i].innerHTML = resN + Names[i].innerHTML.substring(NameColorList[Names[i].innerHTML].length - 1);
            if (Names[i].parentElement.getAttribute('class') == 'legendLabel') {
                NeedsRepeat = true;
            }
        }
    }
    if (NeedsRepeat) {
        setInterval(function(){
            var Names = document.getElementsByClassName('uoj-username');
            for (var i in Names) {
                if (Names[i].innerHTML && Names[i].parentElement.getAttribute('class') == 'legendLabel' && NameColorList[Names[i].innerHTML]) {
                    Names[i].style = 'color:' + NameColorList[Names[i].innerHTML][0];
                    var resN = '';
                    for (var charN = 1; charN < NameColorList[Names[i].innerHTML].length; ++charN) {
                        resN = resN + '<font style="color:' + NameColorList[Names[i].innerHTML][charN] + '">' + Names[i].innerHTML.substring(charN - 1, charN) + '</font>';
                    }
                    Names[i].innerHTML = resN + Names[i].innerHTML.substring(NameColorList[Names[i].innerHTML].length - 1);
                }
            }
        }, 200);
    }
    var Honors = document.getElementsByClassName('uoj-honor');
    for (var j in Honors) {
        if (Honors[j].innerHTML && NameColorList[Honors[j].innerHTML]) {
            Honors[j].style = 'color:' + NameColorList[Honors[j].innerHTML][0];
            var resH = '';
            for (var charH = 1; charH < NameColorList[Honors[j].innerHTML].length; ++charH) {
                resH = resH + '<font style="color:' + NameColorList[Honors[j].innerHTML][charH] + '">' + Honors[j].innerHTML.substring(charH - 1, charH) + '</font>';
            }
            Honors[j].innerHTML = resH + Honors[j].innerHTML.substring(NameColorList[Honors[j].innerHTML].length - 1);
        }
    }
}

function NameBadge() {
    var Names = document.getElementsByClassName('uoj-username');
    for (var i in Names) {
        if (!Names[i].innerHTML) continue;
        var name = Names[i].textContent;
        if (CCFBadgeList[name] && Names[i].parentElement.getAttribute('class') != 'legendLabel') {
            Names[i].innerHTML = Names[i].innerHTML + ' <svg width="1em" height="1em" data-v-303bbf52="" aria-hidden="true" focusable="false" data-prefix="fad" data-icon="badge-check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="margin-bottom:.25em!important;bottom:10px;--fa-primary-color:#fff;--fa-secondary-color:' + CCFBadgeList[name] + ';--fa-secondary-opacity:1;"><g data-v-303bbf52="" class="fa-group"><path data-v-303bbf52="" fill="var(--fa-secondary-color)" d="M512 256a88 88 0 0 0-57.1-82.4A88 88 0 0 0 338.4 57.1a88 88 0 0 0-164.8 0A88 88 0 0 0 57.1 173.6a88 88 0 0 0 0 164.8 88 88 0 0 0 116.5 116.5 88 88 0 0 0 164.8 0 88 88 0 0 0 116.5-116.5A88 88 0 0 0 512 256zm-144.8-44.25l-131 130a11 11 0 0 1-15.55-.06l-75.72-76.33a11 11 0 0 1 .06-15.56L171 224a11 11 0 0 1 15.56.06l42.15 42.49 97.2-96.42a11 11 0 0 1 15.55.06l25.82 26a11 11 0 0 1-.08 15.56z" class="fa-secondary"></path></g></svg>';
        }
        if (TagBadgeList[name] && Names[i].parentElement.getAttribute('class') != 'legendLabel') {
            Names[i].innerHTML = Names[i].innerHTML + ' <span style="background-color:' + TagBadgeList[name][0] + ';padding:0.2em 0.6em;border-radius:.2em;color:#fff;font-size:0.7em;font-weight:bold;display:inline-block">' + TagBadgeList[name][1] + '</span>';
        }
    }
    var Honors = document.getElementsByClassName('uoj-honor');
    for (var j in Honors) {
        if (!Honors[j].innerHTML) continue;
        var honor = Honors[j].textContent;
        if (CCFBadgeList[honor]) {
            Honors[j].innerHTML = Honors[j].innerHTML + ' <svg width="1em" height="1em" data-v-303bbf52="" aria-hidden="true" focusable="false" data-prefix="fad" data-icon="badge-check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="margin-bottom:.25em!important;bottom:10px;--fa-primary-color:#fff;--fa-secondary-color:' + CCFBadgeList[honor] + ';--fa-secondary-opacity:1;"><g data-v-303bbf52="" class="fa-group"><path data-v-303bbf52="" fill="var(--fa-secondary-color)" d="M512 256a88 88 0 0 0-57.1-82.4A88 88 0 0 0 338.4 57.1a88 88 0 0 0-164.8 0A88 88 0 0 0 57.1 173.6a88 88 0 0 0 0 164.8 88 88 0 0 0 116.5 116.5 88 88 0 0 0 164.8 0 88 88 0 0 0 116.5-116.5A88 88 0 0 0 512 256zm-144.8-44.25l-131 130a11 11 0 0 1-15.55-.06l-75.72-76.33a11 11 0 0 1 .06-15.56L171 224a11 11 0 0 1 15.56.06l42.15 42.49 97.2-96.42a11 11 0 0 1 15.55.06l25.82 26a11 11 0 0 1-.08 15.56z" class="fa-secondary"></path></g></svg>';
        }
        if (TagBadgeList[honor]) {
            Honors[j].innerHTML = Honors[j].innerHTML + ' <span style="background-color:' + TagBadgeList[honor][0] + ';padding:0.2em 0.6em;border-radius:.2em;color:#fff;font-size:0.7em;font-weight:bold;display:inline-block">' + TagBadgeList[honor][1] + '</span>';
        }
    }
}