// ==UserScript== // @name GenGen-RMJ // @icon https://cdn.luogu.com.cn/upload/image_hosting/yy27itbl.png // @namespace https://gengen.qzz.io/ // @version 4.7.6.3 // @description GenGen RMJ // @author GenGen 队 // @run-at document-start // @match https://challenges.cloudflare.com/cdn-cgi/challenge-platform/* // @match https://www.luogu.com.cn/* // @match https://atcoder.jp/contests/*/submit?RMJ=1 // @match https://codeforces.com/* // @require https://scriptcat.org/scripts/code/7193/GenGen-RMJ-JL.user.js // @require https://scriptcat.org/scripts/code/5096/GenGen-Cloudflare-RMJ.user.js // @require https://scriptcat.org/scripts/code/7286/GenGen-RMJ-DET.user.js // @connect * // @inject-into page // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant unsafeWindow // @license MIT // ==/UserScript== // (() => { 'use strict'; if (location.hostname === 'challenges.cloudflare.com') { const XHR = (unsafeWindow || window).XMLHttpRequest; if (XHR) { const [o, s] = [XHR.prototype.open, XHR.prototype.send]; XHR.prototype.open = function(m, u) { this._u = u || ''; return o.apply(this, arguments); }; XHR.prototype.send = function(b) { if (this._u) this.timeout = undefined; return s.apply(this, arguments); }; } } const V = '4.7.6.3', P = 1000, T = `[RMJ ${V}]`; const C = { ac: '#52c41a', wa: '#e74c3c', na: '#404040', p: '#0ea5e9', bd: '#e2e8f0', t: '#1e293b', m: '#64748b', bg: '#fff', alt: '#f8fafc' }; const L = (...a) => console.log(T, ...a); const E = (...a) => console.error(T, ...a); const R = fn => document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', fn) : fn(); const W = (sel, cb, ms = 12000) => { const t0 = Date.now(); const iv = setInterval(() => { const el = document.querySelector(sel); if (el) { clearInterval(iv); cb(el); } else if (Date.now() - t0 > ms) clearInterval(iv); }, 120); }; const isL = () => location.hostname === 'www.luogu.com.cn'; const isCF = () => location.hostname === 'codeforces.com'; const SVG = { ok: ``, err: ``, na: `` }; GM_addStyle(` .rmj-trigger{display:inline-flex;align-items:center;gap:8px;padding:8px 16px;background:#fff;color:${C.t};border:1px solid ${C.bd};border-radius:8px;font:600 13px 'JetBrains Mono',monospace;cursor:pointer;transition:.2s;box-shadow:0 1px 3px rgba(0,0,0,.04);user-select:none;margin-right:10px;height:36px} .rmj-trigger:hover{border-color:${C.p};color:${C.p};box-shadow:0 2px 8px rgba(14,165,233,.15);transform:translateY(-1px)} .rmj-trigger img{width:20px;height:20px;border-radius:4px} .rmj-overlay{pointer-events: auto; position:fixed;inset:0;background:rgba(0,0,0,.4);backdrop-filter:blur(4px);z-index:2147483646;display:flex;align-items:center;justify-content:center;opacity:0;visibility:hidden;transition:.25s} .rmj-overlay.show{opacity:1;visibility:visible} .rmj-modal{width:480px;max-height:85vh;background:#fff;border-radius:16px;box-shadow:0 25px 60px rgba(0,0,0,.12);display:flex;flex-direction:column;overflow:hidden;transform:scale(.95) translateY(10px);transition:transform .3s cubic-bezier(.34,1.56,.64,1), height .3s ease} .rmj-pages{flex:1;overflow:hidden;position:relative;min-height:0;height:auto;transition:height .3s ease} .rmj-page:not(.active){visibility:hidden;pointer-events:none;position:absolute;top:0;left:50%;width:50%;height:100%} .rmj-page.active { visibility: visible; pointer-events: auto; opacity: 1; z-index: 1; } .rmj-overlay.show .rmj-modal{transform:scale(1) translateY(0)} .rmj-head{padding:20px 24px 16px;border-bottom:1px solid ${C.bd};display:flex;align-items:center;gap:12px} .rmj-head img{width:36px;height:36px;border-radius:8px} .rmj-title{flex:1;margin:0;font:700 20px 'JetBrains Mono',monospace;background:linear-gradient(135deg,${C.p},#2563eb);-webkit-background-clip:text;-webkit-text-fill-color:transparent} .rmj-close{width:32px;height:32px;border:0;background:0 0;color:${C.m};cursor:pointer;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:20px;transition:.15s} .rmj-close:hover{background:${C.alt};color:${C.t}} .rmj-pages { display: grid; width: 100%; overflow: hidden; transition: height .3s ease; } .rmj-pages-inner { display: contents; } .rmj-page { grid-area: 1 / 1 / 2 / 2; padding: 24px; overflow-y: auto; box-sizing: border-box; visibility: hidden; pointer-events: none; opacity: 0; transition: opacity .3s ease, visibility .3s; } .rmj-welcome-title{font-size:18px;font-weight:700;color:${C.t};margin-bottom:12px} .rmj-update-badge{display:inline-block;padding:3px 10px;background:linear-gradient(135deg,${C.p},#2563eb);color:#fff;border-radius:20px;font-size:11px;font-weight:600;margin-left:8px} .rmj-feat{list-style:none;padding:0;margin:16px 0} .rmj-feat li{display:flex;align-items:flex-start;gap:10px;padding:8px 0;color:${C.m};font-size:14px;line-height:1.5} .rmj-feat li::before{content:'·';flex-shrink:0} .rmj-sec{font-size:11px;font-weight:700;color:${C.m};text-transform:uppercase;letter-spacing:1px;margin:0 0 12px} .rmj-sec:not(:first-child){margin-top:20px} .rmj-card{background:${C.alt};border:1px solid ${C.bd};border-radius:10px;padding:14px 16px;display:flex;align-items:center;justify-content:space-between;transition:.2s} .rmj-card:hover{border-color:${C.p}33;box-shadow:0 2px 8px rgba(14,165,233,.08)} .rmj-card+.rmj-card{margin-top:8px} .rmj-info{display:flex;align-items:center;gap:12px} .rmj-logo{width:32px;height:32px;border-radius:6px;object-fit:contain} .rmj-name{font-size:14px;font-weight:600;color:${C.t}} .rmj-badge{display:inline-flex;align-items:center;gap:4px;padding:4px 12px;border-radius:20px;font-size:12px;font-weight:600} .rmj-badge.on{background:${C.ac}15;color:${C.ac}} .rmj-badge.on::before{content:'';width:6px;height:6px;border-radius:50%;background:${C.ac};animation:pulse 2s infinite} .rmj-badge.off{background:${C.wa}15;color:${C.wa};cursor:pointer;text-decoration:none;transition:.15s} .rmj-badge.off:hover{background:${C.wa}25;transform:translateY(-1px)} .rmj-badge.load{background:#f1f5f9;color:${C.m}} @keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}} .rmj-spin{width:14px;height:14px;border:2px solid ${C.bd};border-top-color:${C.p};border-radius:50%;animation:spin .8s linear infinite} @keyframes spin{to{transform:rotate(360deg)}} .rmj-links{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:12px} .rmj-link{display:flex;align-items:center;gap:8px;padding:10px 12px;background:${C.alt};border:1px solid ${C.bd};border-radius:8px;color:${C.t};text-decoration:none;font-size:13px;font-weight:500;transition:.2s} .rmj-link:hover{border-color:${C.p};color:${C.p};transform:translateY(-1px);box-shadow:0 2px 8px rgba(14,165,233,.1)} .rmj-link svg{width:16px;height:16px;flex-shrink:0} .rmj-foot{padding:16px 24px;border-top:1px solid ${C.bd};display:flex;align-items:center;justify-content:space-between;background:${C.alt}} .rmj-btn{padding:8px 16px;border:1px solid ${C.bd};background:#fff;color:${C.t};border-radius:6px;font-size:13px;font-weight:500;cursor:pointer;transition:.15s} .rmj-btn:hover:not(:disabled){border-color:${C.p};color:${C.p}} .rmj-btn:disabled{opacity:.4;cursor:not-allowed} .rmj-dots{display:flex;gap:6px} .rmj-dot{width:6px;height:6px;border-radius:50%;background:${C.bd};transition:.2s} .rmj-dot.active{background:${C.p};width:18px;border-radius:3px} .rmj-prob{display: inline-flex;align-items: center;transition: all .3s;} .rmj-prob.ac{color:${C.ac};font-weight:bold} .rmj-prob.wa{color:${C.wa};font-weight:bold} .rmj-prob.na{color:#3498db;} .rmj-ico{position:absolute;inset:0;background:0 0;display:flex;align-items:center;justify-content:center;z-index:10;border-radius:inherit;animation:fadeIn .3s} .rmj-ico svg{width:18px;height:18px;animation:popIn .3s cubic-bezier(.34,1.56,.64,1)} .rmj-hide>*:not(.rmj-ico){visibility:hidden!important} @keyframes fadeIn{from{opacity:0}to{opacity:1}} @keyframes popIn{from{transform:scale(.5);opacity:0}to{transform:scale(1);opacity:1}} @keyframes badgePop{0%{transform:scale(.8);opacity:0}60%{transform:scale(1.05)}100%{transform:scale(1);opacity:1}} .rmj-record-badge{animation:badgePop .4s ease-out} .rmj-sel{position:relative;display:inline-block;margin-left:8px} .rmj-sel-btn{position:relative;display:inline-flex;align-items:center;min-width:120px;padding:3px 26px 3px 10px;border:1px solid #ccc;border-radius:3px;background:#fff;font-size:13px;line-height:1.4;cursor:pointer;text-align:left} .rmj-sel-btn::after{content:"";position:absolute;right:10px;top:50%;width:6px;height:6px;border-right:1.5px solid #555;border-bottom:1.5px solid #555;transform:translateY(-65%) rotate(45deg);transition:.2s} .rmj-sel.open .rmj-sel-btn::after{transform:translateY(-35%) rotate(-135deg)} .rmj-sel-menu{position:absolute;top:calc(100% + 4px);left:0;width:100%;margin:0;padding:4px 0;list-style:none;background:#fff;border:1px solid #ccc;border-radius:4px;box-shadow:0 4px 12px rgba(0,0,0,.1);opacity:0;transform:translateY(-8px);pointer-events:none;transition:.2s;z-index:100} .rmj-sel-menu.open{opacity:1;transform:translateY(0);pointer-events:all} .rmj-sel-menu li{padding:3px 12px;cursor:pointer;font-size:14px} .rmj-sel-menu li:hover{background:#f0f9ff} .rmj-refresh-wrap{display:inline-flex;align-items:center;margin-left:8px;cursor:pointer;color:${C.m};transition:.2s} .rmj-refresh-wrap:hover{color:${C.p};transform:rotate(90deg)} .rmj-refresh{width:14px;height:14px} .rmj-switch{position:relative;display:inline-block;width:40px;height:22px} .rmj-switch input{opacity:0;width:0;height:0} .rmj-slider{position:absolute;cursor:pointer;inset:0;background:#ccc;transition:.3s;border-radius:22px} .rmj-slider:before{position:absolute;content:"";height:16px;width:16px;left:3px;bottom:3px;background:#fff;transition:.3s;border-radius:50%} .rmj-switch input:checked + .rmj-slider{background:${C.p}} .rmj-switch input:checked + .rmj-slider:before{transform:translateX(18px)} .rmj-switch input:disabled + .rmj-slider{opacity:.5;cursor:not-allowed} `); let cfM = new Map(), atM = new Map(), cfR = '', atR = ''; let cr = false, lT = null, pT = null, md = null, pg = 0; let cfPollTimer = null; const SPECIAL_ACCOUNTS = ['General0000000826', 'General000000826']; const isSpecialAccount = () => { const cfH = GM_getValue('cf-handle', ''); const atH = GM_getValue('at-handle', ''); return SPECIAL_ACCOUNTS.includes(cfH) || SPECIAL_ACCOUNTS.includes(atH); }; const getDisableSync = () => { if (isSpecialAccount()) return true; let pVal = false; try { const params = new URLSearchParams(location.search); pVal = params.get('rmj-disable-sync') === 'true'; } catch(e) {} if (pVal) return true; // 确保 GM 中始终有明确的值,首次读取时写入默认值 false(默认启用同步) if (GM_getValue('rmj-disable-sync', null) === null) { GM_setValue('rmj-disable-sync', false); } return GM_getValue('rmj-disable-sync', false) === true; }; const capCF = () => { if (!isCF()) return; const try_ = () => { const el = document.querySelector('#header > div.lang-chooser > div:nth-child(2) > a:nth-child(1)'); if (!el) return setTimeout(try_, 1000); const t = el.textContent.trim(); if (t && !['Enter', '登录'].includes(t)) { const o = GM_getValue('cf-handle', ''); if (o !== t) GM_setValue('cf-handle', t); } }; try_(); }; const capAT = () => { cr = true; uM(); GM_xmlhttpRequest({ method: 'GET', url: 'https://atcoder.jp/', timeout: 8000, onload: r => { cr = false; if (r.status !== 200) return uM(); try { const doc = new DOMParser().parseFromString(r.responseText, 'text/html'); const el = doc.querySelector('#navbar-collapse > ul.nav.navbar-nav.navbar-right > li:nth-child(2) > a'); if (!el || el.textContent.trim() === 'Sign Up') return uM(); const h = el.textContent.trim(); const o = GM_getValue('at-handle', ''); if (o !== h) GM_setValue('at-handle', h); uM(); } catch (e) { E(e); } }, onerror: () => { cr = false; uM(); } }); }; const rC = () => { try { const cR = GM_getValue('cf-submissions-cache', '[]'); const aR = GM_getValue('at-submissions-cache', '[]'); if (cR !== cfR) { cfR = cR; cfM.clear(); JSON.parse(cR).forEach(s => { const m = s?.taskDisplay?.match(/CF[A-Z0-9]+/i); if (m) { const k = m[0].toUpperCase(), v = s.status || null; if (!cfM.has(k) || (cfM.get(k) !== 'OK' && v === 'OK')) cfM.set(k, v); } }); } if (aR !== atR) { atR = aR; atM.clear(); JSON.parse(aR).forEach(s => { if (s?.taskKey) { const k = s.taskKey.toLowerCase(), v = s.status || null; if (!atM.has(k) || (atM.get(k) !== 'AC' && v === 'AC')) atM.set(k, v); } }); } } catch (e) { E(e); } }; const qS = pid => { if (/^CF[A-Z0-9]+$/i.test(pid)) { const v = cfM.get(pid.toUpperCase()); return v === 'OK' ? 'AC' : v ? 'WA' : 'NONE'; } if (/^AT_/i.test(pid)) { const k = pid.replace(/^AT_/i, '').toLowerCase(); const v = atM.get(k); return v === 'AC' ? 'AC' : v ? 'WA' : 'NONE'; } return null; }; const uL = () => { rC(); document.querySelectorAll('.row').forEach(row => { const [sc, pc] = row.children; if (!pc) return; const m = pc.textContent.trim().match(/^(\S+)/); if (!m) return; const st = qS(m[1]); if (!st) { const ov = sc.querySelector('.rmj-ico'); if (ov) { ov.remove(); sc.classList.remove('rmj-hide'); } return; } let ov = sc.querySelector('.rmj-ico'); if (!ov) { ov = document.createElement('div'); ov.className = 'rmj-ico'; sc.style.position = 'relative'; sc.appendChild(ov); sc.classList.add('rmj-hide'); } const icon = st === 'AC' ? SVG.ok : st === 'WA' ? SVG.err : SVG.na; if (ov.dataset.s !== st) { ov.innerHTML = icon; ov.dataset.s = st; } }); }; const sL = () => { if (!lT) { uL(); lT = setInterval(uL, P); } }; const xL = () => { if (lT) { clearInterval(lT); lT = null; } }; const uP = () => { rC(); const pid = location.pathname.split('/problem/')[1]; if (!pid) return; const st = qS(pid); if (!st) return; const link = document.querySelectorAll('a[href*="/record/list?pid="]')[0]; if (!link) return; let tag = link.querySelector('.rmj-prob'); if (!tag) { const orig = link.querySelector('span'); if (orig) orig.style.display = 'none'; tag = document.createElement('span'); tag.className = 'rmj-prob'; link.appendChild(tag); } const way = document.querySelectorAll('a[href*="https://help.luogu.com.cn/manual/luogu/problem/remote-judge"]')[0]; if(way && way.textContent!="GenGen RMJ"){ console.log(way); way.textContent="GenGen RMJ"; way.href="https://gengen.qzz.io/rmj/"; } const cls = st === 'AC' ? 'ac' : st === 'WA' ? 'wa' : 'na'; const txt = st === 'AC' ? 'Accepted' : st === 'WA' ? 'Unaccepted' : '暂无'; if (tag.dataset.s !== st) { tag.className = 'rmj-prob ' + cls; tag.innerHTML = txt; tag.dataset.s = st; } }; const sP = () => { if (!pT) { uP(); pT = setInterval(uP, P); } }; const xP = () => { if (pT) { clearInterval(pT); pT = null; } }; const startCfPoll = () => { if (cfPollTimer) clearInterval(cfPollTimer); const initialHandle = GM_getValue('cf-handle', ''); let checks = 0; cfPollTimer = setInterval(() => { checks++; const currentHandle = GM_getValue('cf-handle', ''); if (currentHandle !== initialHandle || checks > 60) { clearInterval(cfPollTimer); cfPollTimer = null; uM(); } }, 1000); uM(); }; const bM = () => { if (md) md.remove(); md = document.createElement('div'); md.className = 'rmj-overlay'; md.innerHTML = `

GenGen RMJ

👋 欢迎使用 GenGen RMJ 4 v${V}

在洛谷上无缝刷 Codeforces 和 AtCoder 题目,同步提交记录。

  • 请点击下一页来绑定你的账户!
  • 自动同步 CF/AT 账号提交记录
  • 题目列表和题单直观显示通过状态
  • Cloudflare 验证加速绕过
  • 记录详细查看功能
  • 最新更新:完善用户面板体验 & 叕双修复 CodeForces 无法提交的 bug
账号绑定
Codeforces
AtCoder
设置
自动同步
快捷链接
`; document.body.appendChild(md); md.querySelector('.rmj-close').onclick = () => { GM_setValue('rmj-version-shown', V); hiM(); }; md.querySelector('.rmj-prev').onclick = () => swP(0); md.querySelector('.rmj-next').onclick = () => swP(1); uM(); }; const uM = () => { if (!md) return; const cfH = GM_getValue('cf-handle', ''), atH = GM_getValue('at-handle', ''); const cfEl = md.querySelector('#rmj-cf'), atEl = md.querySelector('#rmj-at'); const refreshIcon = ``; if (cfPollTimer) { cfEl.innerHTML = `同步中...`; } else if (cfH) { cfEl.innerHTML = `${cfH}${refreshIcon}`; } else { cfEl.innerHTML = `去绑定 →`; } if (cr) { atEl.innerHTML = `刷新中...`; } else if (atH) { atEl.innerHTML = `${atH}${refreshIcon}`; } else { atEl.innerHTML = `去绑定 →`; } const cfBind = md.querySelector('#rmj-cf-bind'); if (cfBind) { cfBind.onclick = (e) => { startCfPoll(); }; } const cfRefresh = md.querySelector('#rmj-cf .rmj-refresh-wrap'); if (cfRefresh) { cfRefresh.onclick = () => { window.open('https://codeforces.com/enter', '_blank'); startCfPoll(); }; } const atBind = md.querySelector('#rmj-at-bind'); if (atBind) { atBind.onclick = (e) => { e.preventDefault(); capAT(); }; } const atRefresh = md.querySelector('#rmj-at .rmj-refresh-wrap'); if (atRefresh) { atRefresh.onclick = () => { capAT(); }; } const syncToggle = md.querySelector('#rmj-disable-sync'); if (syncToggle) { // 正向语义:checked = true 表示"自动同步已开启" // getDisableSync() 返回 true 表示同步被禁用,所以取反 const isDisabled = getDisableSync(); syncToggle.checked = !isDisabled; if (isSpecialAccount()) { syncToggle.checked = false; // 特殊账号强制关闭同步 syncToggle.disabled = true; syncToggle.title = '特殊账号无法修改同步设置'; } syncToggle.onchange = async () => { if (isSpecialAccount()) { syncToggle.checked = false; // 强制保持关闭 return; } const disabled = !syncToggle.checked; GM_setValue('at-submissions-cache', '[]'); GM_setValue('cf-submissions-cache', '[]'); GM_setValue('at-last-update', '0'); GM_setValue('cf-0last-update', '0'); uL(); uP(); }; } }; const swP = idx => { if (idx === pg) return; const pagesContainer = md.querySelector('.rmj-pages'); const allPages = md.querySelectorAll('.rmj-page'); const targetPage = allPages[idx]; const dots = md.querySelectorAll('.rmj-dot'); const prevBtn = md.querySelector('.rmj-prev'), nextBtn = md.querySelector('.rmj-next'); allPages.forEach((p, i) => p.classList.toggle('active', i === idx)); if (targetPage && pagesContainer) { pagesContainer.style.height = targetPage.scrollHeight + 'px'; } dots.forEach((d, i) => d.classList.toggle('active', i === idx)); prevBtn.disabled = idx === 0; nextBtn.disabled = idx === dots.length - 1; pg = idx; if (idx === 1 && !GM_getValue('at-handle', '') && !cr) capAT(); }; const shM = (page = 0) => { if (!md) bM(); pg = page; const pagesContainer = md.querySelector('.rmj-pages'); const allPages = md.querySelectorAll('.rmj-page'); const targetPage = allPages[page]; const dots = md.querySelectorAll('.rmj-dot'); const prevBtn = md.querySelector('.rmj-prev'), nextBtn = md.querySelector('.rmj-next'); allPages.forEach((p, i) => p.classList.toggle('active', i === page)); requestAnimationFrame(() => { if (targetPage && pagesContainer) { pagesContainer.style.height = targetPage.scrollHeight + 'px'; } }); dots.forEach((d, i) => d.classList.toggle('active', i === page)); prevBtn.disabled = page === 0; nextBtn.disabled = page === dots.length - 1; md.classList.add('show'); }; const hiM = () => { if (md) md.classList.remove('show'); }; const chV = () => { if (GM_getValue('rmj-version-shown', '') !== V) { setTimeout(() => shM(0), 500); } }; const iB = () => { if (location.pathname !== '/' || document.querySelector('.rmj-trigger')) return; W('.user-nav', nav => { if (nav.dataset.rmj) return; nav.dataset.rmj = '1'; const btn = document.createElement('button'); btn.className = 'rmj-trigger'; btn.innerHTML = `GenGen RMJ`; btn.onclick = () => shM(1); nav.parentElement.insertBefore(btn, nav); }); }; const hP = () => { const p = location.pathname; if (!p.startsWith('/problem/CF') && !p.startsWith('/problem/AT')) return; const rmj = p.startsWith('/problem/CF') ? '1' : '2'; const pid = p.split('/problem/')[1]; if (!pid) return; W('.side', side => { new MutationObserver(() => { side.querySelectorAll('a[href*="/record/list?pid="]').forEach(link => { if (link.dataset.rmjHook) return; link.dataset.rmjHook = '1'; link.addEventListener('click', e => { if (e.button !== 0) return; e.preventDefault(); e.stopImmediatePropagation(); const u = new URL('/record/list', location.origin); const sp = new URLSearchParams(location.search); for (const [k, v] of sp) u.searchParams.set(k, v); u.searchParams.set('pid', pid); u.searchParams.set('rmj', rmj); location.href = u.toString(); }, true); link.addEventListener('mousedown', e => { if (e.button !== 1) return; const u = new URL('/record/list', location.origin); const sp = new URLSearchParams(location.search); for (const [k, v] of sp) u.searchParams.set(k, v); u.searchParams.set('pid', pid); u.searchParams.set('rmj', rmj); link.href = u.toString(); }, true); }); uP(); }).observe(side, { childList: true, subtree: true }); }); uP();sP(); }; const iS = () => { if (!location.pathname.startsWith('/record/list')) return; W('section b', b => { if (b.dataset.rmj) return; b.dataset.rmj = '1'; const w = document.createElement('span'); w.className = 'rmj-sel'; w.innerHTML = ` `; b.after(w); const btn = w.querySelector('.rmj-sel-btn'); const menu = w.querySelector('.rmj-sel-menu'); btn.addEventListener('click', e => { e.stopPropagation(); w.classList.toggle('open'); menu.classList.toggle('open'); }); menu.querySelectorAll('li').forEach(li => { li.addEventListener('click', e => { e.stopPropagation(); const val = li.dataset.value; btn.textContent = li.textContent; w.classList.remove('open'); menu.classList.remove('open'); const p = new URLSearchParams(location.search); val ? p.set('rmj', val) : p.delete('rmj'); location.search = p.toString(); }); }); document.addEventListener('click', () => { w.classList.remove('open'); menu.classList.remove('open'); }); const cur = new URLSearchParams(location.search).get('rmj') || ''; const act = menu.querySelector(`li[data-value="${cur}"]`); if (act) btn.textContent = act.textContent; }); }; let prev = location.pathname; const onR = () => { const cur = location.pathname; if (cur === prev) return; const wasL = prev.startsWith('/training') || prev.startsWith('/problem/list'); const nowL = cur.startsWith('/training') || cur.startsWith('/problem/list'); const wasP = prev.startsWith('/problem/CF') || prev.startsWith('/problem/AT'); const nowP = cur.startsWith('/problem/CF') || cur.startsWith('/problem/AT'); if (wasL && !nowL) xL(); if (!wasL && nowL) sL(); if (wasP && !nowP) xP(); if (!wasP && nowP) hP(); prev = cur; }; const main = () => { if (isCF()) { capCF(); return; } if (!isL()) return; chV(); iB(); hP(); iS(); if (location.pathname.startsWith('/training') || location.pathname.startsWith('/problem/list')) sL(); setInterval(onR, 200); addEventListener('beforeunload', () => { xL(); xP(); }); }; R(main); })();