// ==UserScript== // @name Universal OJ // @namespace http://tampermonkey.net/ // @version 1.2 // @description OJ 代码编辑器 // @author Sunse666 // @match *://www.luogu.com.cn/problem/* // @match *://www.luogu.com.cn/contest/*/problem/* // @match *://codeforces.com/contest/*/problem/* // @match *://codeforces.com/problemset/problem/*/* // @match *://codeforces.com/gym/*/problem/* // @match *://codeforces.com/group/*/contest/*/problem/* // @match *://ac.nowcoder.com/acm/problem/* // @match *://ac.nowcoder.com/acm/contest/* // @match *://vjudge.net/problem/* // @match *://*/problem/* // @match *://*/contest/*/problem/* // @grant GM_addStyle // @require https://cdn.bootcdn.net/ajax/libs/highlight.js/11.11.1/highlight.min.js // @require https://cdn.bootcdn.net/ajax/libs/highlight.js/11.11.1/languages/go.min.js // @run-at document-end // ==/UserScript== (function() { 'use strict'; console.log('[Universal OJ] 脚本启动'); const platformConfigs = { luogu: { name: '洛谷', match: /luogu\.com\.cn/, selectors: { title: '.lfe-h1, h1[class*="title"]', content: '.lfe-marked-wrap, .problem-markdown-content', buttonContainer: '.ide-toolbar .actions, .problem .actions', submitBtn: 'a[class*="title"]:has(.fa-paper-plane)', codeEditor: '.cm-editor, .CodeMirror, textarea.lfe-code', problemId: () => { const match = window.location.pathname.match(/\/problem\/(P\d+|[A-Z]+\d+)/); return match ? match[1] : 'unknown'; } }, getProblemInfo: function() { let html = ''; const titleEl = document.querySelector(this.selectors.title); if (titleEl) { html += `

${escapeHtml(titleEl.textContent.trim())}

`; } const contentEl = document.querySelector('.problem[data-v-3bac9eed]'); if (contentEl) { const cloned = contentEl.cloneNode(true); cloned.querySelectorAll('button, .lfe-caption, .problem-block-actions, .io-sample').forEach(el => el.remove()); cloned.querySelectorAll('.lfe-h2').forEach(h2 => { h2.style.color = '#cba6f7'; h2.style.fontSize = '14px'; h2.style.marginTop = '15px'; h2.style.marginBottom = '8px'; }); cloned.querySelectorAll('pre code').forEach(code => { code.style.background = '#11111b'; code.style.padding = '12px'; code.style.borderRadius = '6px'; code.style.color = '#a6e3a1'; code.style.fontSize = '12px'; }); html += `
${cloned.innerHTML}
`; } const samples = document.querySelectorAll('.io-sample'); if (samples.length > 0) { html += `
样例数据
`; samples.forEach((sample, idx) => { const inputEl = sample.querySelector('.io-sample-block:first-child pre'); const outputEl = sample.querySelector('.io-sample-block:last-child pre'); if (inputEl || outputEl) { html += `
`; html += `

样例 ${idx + 1}

`; if (inputEl) { html += `

输入:

`; html += `
${escapeHtml(inputEl.textContent)}
`; } if (outputEl) { html += `

输出:

`; html += `
${escapeHtml(outputEl.textContent)}
`; } html += `
`; } }); } return html || '

无法获取题目信息

'; }, syncCode: function(code) { const cmElement = document.querySelector('.cm-editor'); if (cmElement) { if (cmElement.cmView && cmElement.cmView.view) { const view = cmElement.cmView.view; view.dispatch({ changes: {from: 0, to: view.state.doc.length, insert: code} }); console.log('[Universal OJ] 已通过 CodeMirror 6 API 同步代码'); return true; } const contentEl = cmElement.querySelector('.cm-content[contenteditable="true"]'); if (contentEl) { contentEl.textContent = code; contentEl.dispatchEvent(new Event('input', { bubbles: true })); console.log('[Universal OJ] 已通过 contenteditable 同步代码'); return true; } } const textarea = document.querySelector('textarea[class*="cm-"], textarea.lfe-code'); if (textarea) { textarea.value = code; textarea.dispatchEvent(new Event('input', { bubbles: true })); console.log('[Universal OJ] 已通过 textarea 同步代码'); return true; } return false; } }, nowcoder: { name: '牛客网', match: /nowcoder\.com/, selectors: { title: '.terminal-topic h2.subject-item-title', content: '.terminal-topic', buttonContainer: '.question-operate, .terminal-topic-operation', submitBtn: 'button.runcode-btn, button[type="submit"]', codeEditor: '.CodeMirror, #codeMirror, textarea[name="code"]', problemId: () => { const problemMatch = window.location.pathname.match(/\/acm\/problem\/(\d+)/); if (problemMatch) { return problemMatch[1]; } const contestMatch = window.location.pathname.match(/\/acm\/contest\/(\d+)\/([A-Z])/); if (contestMatch) { return `contest_${contestMatch[1]}_${contestMatch[2]}`; } return 'unknown'; } }, getProblemInfo: function() { let html = ''; function cleanKatexText(element) { const cloned = element.cloneNode(true); cloned.querySelectorAll('.katex-mathml').forEach(el => el.remove()); cloned.querySelectorAll('.katex-html').forEach(el => { const text = el.textContent.trim(); const textNode = document.createTextNode(text); el.parentNode.replaceChild(textNode, el); }); cloned.querySelectorAll('.katex').forEach(el => { const text = el.textContent.trim(); const textNode = document.createTextNode(text); el.parentNode.replaceChild(textNode, el); }); return cloned; } const titleEl = document.querySelector('h2.subject-item-title'); if (titleEl) { const titleText = titleEl.textContent.trim().replace(/只看题目描述.*$/s, '').trim(); html += `

${escapeHtml(titleText)}

`; } const descEl = document.querySelector('.subject-describe .subject-question'); if (descEl) { const cleaned = cleanKatexText(descEl); html += `
`; html += `
题目描述
`; html += `
${cleaned.innerHTML}
`; html += `
`; } const inputDescTitle = Array.from(document.querySelectorAll('h2')).find(h => h.textContent.includes('输入描述')); if (inputDescTitle) { const inputDescContent = inputDescTitle.nextElementSibling; if (inputDescContent && inputDescContent.tagName === 'PRE') { const cleaned = cleanKatexText(inputDescContent); html += `
`; html += `
输入描述
`; html += `
${cleaned.textContent}
`; html += `
`; } } const outputDescTitle = Array.from(document.querySelectorAll('h2')).find(h => h.textContent.includes('输出描述')); if (outputDescTitle) { const outputDescContent = outputDescTitle.nextElementSibling; if (outputDescContent && outputDescContent.tagName === 'PRE') { const cleaned = cleanKatexText(outputDescContent); html += `
`; html += `
输出描述
`; html += `
${cleaned.textContent}
`; html += `
`; } } const exampleSection = document.querySelector('.question-oi'); if (exampleSection) { html += `
示例
`; const inputDiv = exampleSection.querySelector('.question-oi-mod:nth-child(1) .question-oi-cont pre'); const outputDiv = exampleSection.querySelector('.question-oi-mod:nth-child(2) .question-oi-cont pre'); if (inputDiv || outputDiv) { html += `
`; if (inputDiv) { html += `

输入:

`; html += `
${escapeHtml(inputDiv.textContent)}
`; } if (outputDiv) { html += `

输出:

`; html += `
${escapeHtml(outputDiv.textContent)}
`; } html += `
`; } const explanationDiv = exampleSection.querySelector('.question-oi-mod:last-child .question-oi-cont pre'); if (explanationDiv) { const cleaned = cleanKatexText(explanationDiv); html += `

说明:

`; html += `
${cleaned.textContent}
`; } } return html || '

无法获取题目信息

'; }, syncCode: function(code) { const cmElement = document.querySelector('.CodeMirror'); if (cmElement && cmElement.CodeMirror) { cmElement.CodeMirror.setValue(code); console.log('[Universal OJ] 已通过 CodeMirror API 同步代码'); return true; } const cmById = document.getElementById('codeMirror'); if (cmById && cmById.CodeMirror) { cmById.CodeMirror.setValue(code); console.log('[Universal OJ] 已通过 CodeMirror (ID) 同步代码'); return true; } const textarea = document.querySelector('textarea[name="code"]'); if (textarea) { textarea.value = code; textarea.dispatchEvent(new Event('input', { bubbles: true })); textarea.dispatchEvent(new Event('change', { bubbles: true })); console.log('[Universal OJ] 已通过 textarea 同步代码'); return true; } return false; } }, codeforces: { name: 'Codeforces', match: /codeforces\.com/, selectors: { title: '.problem-statement .header .title', content: '.problem-statement', buttonContainer: '.second-level-menu, .sidebox .rtable, .problem-statement .header', submitBtn: 'input[type="submit"]', codeEditor: '.CodeMirror, #sourceCodeTextarea', problemId: () => { const path = window.location.pathname; const m1 = path.match(/\/(contest|gym)\/(\d+)\/problem\/([A-Z]\d?)/); if (m1) return `cf_${m1[2]}${m1[3]}`; const m2 = path.match(/\/problemset\/problem\/(\d+)\/([A-Z]\d?)/); if (m2) return `cf_${m2[1]}${m2[2]}`; return 'cf_unknown'; } }, getProblemInfo: function() { const root = document.querySelector('.problem-statement'); if (!root) return '

无法找到题面

'; const cloned = root.cloneNode(true); const header = cloned.querySelector('.header'); let headerHtml = ''; if (header) { const title = header.querySelector('.title')?.textContent || ''; const time = header.querySelector('.time-limit')?.textContent.replace('time limit per test', '').trim() || ''; const memory = header.querySelector('.memory-limit')?.textContent.replace('memory limit per test', '').trim() || ''; headerHtml = `

${escapeHtml(title)}

⏱️ ${time} 💾 ${memory}
`; header.remove(); } cloned.querySelectorAll('.input-output-copier').forEach(el => el.remove()); cloned.querySelectorAll('.tex-span').forEach(span => { span.style.fontFamily = '"Times New Roman", Times, serif'; span.style.fontSize = '110%'; }); cloned.querySelectorAll('.section-title').forEach(st => { st.style.color = '#cba6f7'; st.style.fontSize = '14px'; st.style.fontWeight = 'bold'; st.style.marginTop = '18px'; st.style.marginBottom = '8px'; st.style.borderLeft = '3px solid #cba6f7'; st.style.paddingLeft = '8px'; }); const sampleTest = cloned.querySelector('.sample-tests'); if (sampleTest) { sampleTest.querySelectorAll('.input, .output').forEach(block => { block.style.marginBottom = '10px'; const title = block.querySelector('.title'); if (title) { title.style.color = '#f9e2af'; title.style.fontSize = '12px'; title.style.marginBottom = '4px'; } const pre = block.querySelector('pre'); if (pre) { pre.style.background = '#11111b'; pre.style.padding = '10px'; pre.style.borderRadius = '6px'; pre.style.color = '#a6e3a1'; pre.style.border = '1px solid #45475a'; pre.style.margin = '0'; } }); } return `
${headerHtml} ${cloned.innerHTML}
`; }, syncCode: function(code) { const cmElement = document.querySelector('.CodeMirror'); if (cmElement && cmElement.CodeMirror) { cmElement.CodeMirror.setValue(code); console.log('[Universal OJ] 已通过 CodeMirror API 同步代码'); return true; } const textarea = document.getElementById('sourceCodeTextarea'); if (textarea) { textarea.value = code; textarea.dispatchEvent(new Event('input', { bubbles: true })); textarea.dispatchEvent(new Event('change', { bubbles: true })); console.log('[Universal OJ] 已通过 textarea 同步代码'); return true; } return false; } }, vjudge: { name: 'Virtual Judge', match: /vjudge\.net/, selectors: { title: '#prob-title h2', content: '#frame-description', buttonContainer: '#prob-title', submitBtn: 'a[data-target="#submitModal"]', codeEditor: '#solution', problemId: () => { const match = window.location.pathname.match(/\/problem\/(.+)/); return match ? `vj_${match[1].replace(/[^a-zA-Z0-9]/g, '_')}` : 'vj_unknown'; } }, getProblemInfo: function() { return new Promise((resolve) => { let html = ''; const titleEl = document.querySelector('#prob-title h2'); if (titleEl) { const titleClone = titleEl.cloneNode(true); titleClone.querySelectorAll('#btn-fav, .glyphicon, i').forEach(el => el.remove()); const titleText = titleClone.textContent.trim(); html += `

${escapeHtml(titleText)}

`; } const originLink = document.querySelector('#prob-title .origin a'); if (originLink) { const originText = originLink.textContent.trim(); const originHref = originLink.href; html += `

🔗 来源: ${escapeHtml(originText)}

`; } const waitForIframe = (attempts = 0) => { if (attempts > 40) { html += `

❌ 题目加载超时,请刷新页面

`; resolve(html); return; } const iframe = document.querySelector('#frame-description'); if (!iframe) { setTimeout(() => waitForIframe(attempts + 1), 250); return; } try { const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; if (!iframeDoc || !iframeDoc.body) { setTimeout(() => waitForIframe(attempts + 1), 250); return; } const container = iframeDoc.querySelector('#description-container dd'); if (!container || container.innerHTML.trim().length < 100) { setTimeout(() => waitForIframe(attempts + 1), 250); return; } const cloned = container.cloneNode(true); cloned.querySelectorAll('style, script, .copier, .data-json-container').forEach(el => el.remove()); cloned.querySelectorAll('h3').forEach(h => { h.style.cssText = ` color: #cba6f7 !important; font-size: 14px !important; font-weight: bold !important; margin: 20px 0 10px 0 !important; border-left: 3px solid #cba6f7 !important; padding-left: 8px !important; `; }); cloned.querySelectorAll('div[style*="padding"]').forEach(div => { div.style.cssText = ` color: #cdd6f4 !important; line-height: 1.8 !important; padding: 0 0 20px 0 !important; font-size: 13px !important; `; }); cloned.querySelectorAll('p').forEach(p => { p.style.cssText = ` color: #cdd6f4 !important; line-height: 1.8 !important; margin-bottom: 12px !important; font-size: 13px !important; `; }); cloned.querySelectorAll('pre').forEach(pre => { if (!pre.closest('table.vjudge_sample')) { pre.style.cssText = ` background: #11111b !important; padding: 12px !important; border-radius: 6px !important; color: #a6e3a1 !important; font-size: 12px !important; font-family: 'Consolas', 'Monaco', monospace !important; overflow-x: auto !important; margin: 8px 0 !important; border: 1px solid #45475a !important; white-space: pre-wrap !important; `; } }); cloned.querySelectorAll('table.vjudge_sample').forEach(table => { table.style.cssText = ` width: 100% !important; border-collapse: collapse !important; margin: 10px 0 20px 0 !important; background: transparent !important; `; table.querySelectorAll('thead th').forEach(th => { th.querySelectorAll('.copier').forEach(el => el.remove()); th.style.cssText = ` background: #313244 !important; color: #f9e2af !important; padding: 10px !important; border: 1px solid #45475a !important; font-size: 13px !important; font-weight: bold !important; text-align: left !important; `; }); table.querySelectorAll('tbody td').forEach(td => { td.style.cssText = ` border: 1px solid #45475a !important; padding: 0 !important; vertical-align: top !important; background: #1e1e2e !important; `; const pre = td.querySelector('pre'); if (pre) { pre.style.cssText = ` background: #11111b !important; padding: 10px !important; margin: 0 !important; border: none !important; border-radius: 0 !important; color: #a6e3a1 !important; font-size: 12px !important; font-family: 'Consolas', 'Monaco', monospace !important; white-space: pre !important; overflow-x: auto !important; `; } }); }); cloned.querySelectorAll('.katex').forEach(katex => { katex.style.cssText = ` font-size: 1.1em !important; color: #f5e0dc !important; `; }); cloned.querySelectorAll('.katex-mathml').forEach(el => { el.style.display = 'none'; }); cloned.querySelectorAll('img').forEach(img => { if (img.src && !img.src.startsWith('http')) { img.src = 'https://vjudge.net' + (img.src.startsWith('/') ? img.src : '/' + img.src); } img.style.cssText = ` max-width: 100% !important; height: auto !important; display: block !important; margin: 15px auto !important; border-radius: 6px !important; border: 1px solid #45475a !important; `; }); html += `
${cloned.innerHTML}
`; resolve(html || '

无法获取题目信息

'); } catch (error) { console.error('[Universal OJ] VJudge iframe 访问错误:', error); if (error.name === 'SecurityError') { html += `

⚠️ 由于浏览器安全限制,无法直接读取题目内容

`; html += `

请在新标签页打开原题链接查看完整题面

`; resolve(html); } else { setTimeout(() => waitForIframe(attempts + 1), 250); } } }; waitForIframe(0); }); }, syncCode: function(code) { const submitLink = document.querySelector('a[data-target="#submitModal"]'); if (!submitLink) { console.error('[Universal OJ] VJudge: 未找到提交按钮'); return false; } submitLink.click(); setTimeout(() => { const cmElement = document.querySelector('#submitModal .CodeMirror'); if (cmElement && cmElement.CodeMirror) { cmElement.CodeMirror.setValue(code); console.log('[Universal OJ] VJudge: 已通过 CodeMirror 同步代码'); return true; } const textarea = document.querySelector('#submitModal textarea, #solution'); if (textarea) { textarea.value = code; textarea.dispatchEvent(new Event('input', { bubbles: true })); textarea.dispatchEvent(new Event('change', { bubbles: true })); console.log('[Universal OJ] VJudge: 已同步代码到提交框'); return true; } console.warn('[Universal OJ] VJudge: 未找到代码编辑器'); }, 600); return true; } }, jxau: { name: 'JXAU OJ', match: (url) => { if (/luogu\.com\.cn|codeforces\.com|nowcoder\.com/.test(url)) { return false; } return /\/(problem|contest)\//.test(url); }, selectors: { title: '.ivu-card-head .panel-title div[data-v-6e5e6c6e], .panel-title, .ivu-card-head span', content: '#problem-content.markdown-body, .markdown-body, .ivu-card-body .panel-body', buttonContainer: '.ivu-card-body, .panel-body', submitBtn: 'button:has-text("提交"), button:has-text("Submit")', codeEditor: '.CodeMirror, textarea[name="code"]', problemId: () => { const match = window.location.pathname.match(/\/problem\/(\d+)/); return match ? match[1] : 'unknown'; } }, getProblemInfo: function() { try { let html = ''; const titleElement = document.querySelector('.ivu-card-head .panel-title div[data-v-6e5e6c6e]') || document.querySelector('.panel-title div') || document.querySelector('.ivu-card-head span'); if (titleElement) { const title = titleElement.textContent.trim(); html += `

${escapeHtml(title)}

`; } const problemContent = document.querySelector('#problem-content.markdown-body'); if (problemContent) { const clonedContent = problemContent.cloneNode(true); clonedContent.querySelectorAll('button, input, textarea, select, .copy, .ivu-icon-clipboard').forEach(el => el.remove()); const sections = clonedContent.querySelectorAll('p.title'); sections.forEach(titleEl => { const titleText = titleEl.textContent.trim(); if (titleText.includes('Sample Input') || titleText.includes('Sample Output')) { return; } titleEl.style.color = '#cba6f7'; titleEl.style.fontSize = '14px'; titleEl.style.fontWeight = 'bold'; titleEl.style.marginTop = '20px'; titleEl.style.marginBottom = '10px'; titleEl.style.paddingBottom = '6px'; titleEl.style.borderBottom = '1px solid #45475a'; titleEl.style.display = 'block'; }); clonedContent.querySelectorAll('p.content').forEach(contentEl => { contentEl.style.color = '#cdd6f4'; contentEl.style.lineHeight = '1.8'; contentEl.style.marginBottom = '15px'; contentEl.style.display = 'block'; contentEl.querySelectorAll('span[style*="color"]').forEach(span => { span.style.color = '#cdd6f4'; }); }); clonedContent.querySelectorAll('code').forEach(code => { if (!code.closest('pre')) { code.style.background = '#11111b'; code.style.padding = '2px 6px'; code.style.borderRadius = '4px'; code.style.color = '#f38ba8'; code.style.fontSize = '12px'; code.style.fontFamily = "'Consolas', 'Monaco', monospace"; } }); clonedContent.querySelectorAll('pre').forEach(pre => { if (!pre.closest('.sample-input') && !pre.closest('.sample-output')) { pre.style.background = '#11111b'; pre.style.padding = '12px'; pre.style.borderRadius = '6px'; pre.style.color = '#a6e3a1'; pre.style.fontSize = '12px'; pre.style.fontFamily = "'Consolas', 'Monaco', monospace"; pre.style.overflowX = 'auto'; pre.style.margin = '10px 0'; pre.style.whiteSpace = 'pre'; } }); const mainContent = clonedContent.cloneNode(true); mainContent.querySelectorAll('.flex-container.sample, .sample-input, .sample-output').forEach(el => el.remove()); html += `
${mainContent.innerHTML}
`; const sampleContainers = problemContent.querySelectorAll('.flex-container.sample'); if (sampleContainers.length > 0) { html += `
样例数据
`; sampleContainers.forEach((container, index) => { const inputDiv = container.querySelector('.sample-input'); const outputDiv = container.querySelector('.sample-output'); html += `
`; html += `

样例 ${index + 1}

`; if (inputDiv) { const inputPre = inputDiv.querySelector('pre'); if (inputPre) { html += `

输入:

`; html += `
${escapeHtml(inputPre.textContent)}
`; } } if (outputDiv) { const outputPre = outputDiv.querySelector('pre'); if (outputPre) { html += `

输出:

`; html += `
${escapeHtml(outputPre.textContent)}
`; } } html += `
`; }); } return html; } return `

无法获取题目内容

`; } catch (e) { console.error('[Universal OJ] JXAU 获取题目信息失败:', e); return `

题目信息加载失败: ${e.message}

`; } }, syncCode: function(code) { const cmElement = document.querySelector('.CodeMirror'); if (cmElement && cmElement.CodeMirror) { cmElement.CodeMirror.setValue(code); console.log('[Universal OJ] 已通过 CodeMirror API 同步代码'); return true; } const textarea = document.querySelector('.CodeMirror textarea') || document.querySelector('textarea[name="code"]') || document.querySelector('#editor textarea'); if (textarea) { textarea.value = code; textarea.dispatchEvent(new Event('input', { bubbles: true })); textarea.dispatchEvent(new Event('change', { bubbles: true })); console.log('[Universal OJ] 已通过 Textarea 同步代码'); return true; } return false; } } }; function detectPlatform() { const url = window.location.href; if (platformConfigs.luogu.match.test(url)) { console.log(`[Universal OJ] 检测到平台: 洛谷`); return { key: 'luogu', ...platformConfigs.luogu }; } if (platformConfigs.codeforces.match.test(url)) { console.log(`[Universal OJ] 检测到平台: Codeforces`); return { key: 'codeforces', ...platformConfigs.codeforces }; } if (platformConfigs.nowcoder.match.test(url)) { console.log(`[Universal OJ] 检测到平台: 牛客网`); return { key: 'nowcoder', ...platformConfigs.nowcoder }; } if (platformConfigs.vjudge.match.test(url)) { console.log(`[Universal OJ] 检测到平台: Virtual Judge`); return { key: 'vjudge', ...platformConfigs.vjudge }; } if (typeof platformConfigs.jxau.match === 'function') { if (platformConfigs.jxau.match(url)) { console.log(`[Universal OJ] 检测到平台: JXAU OJ`); return { key: 'jxau', ...platformConfigs.jxau }; } } else if (platformConfigs.jxau.match.test(url)) { console.log(`[Universal OJ] 检测到平台: JXAU OJ`); return { key: 'jxau', ...platformConfigs.jxau }; } console.log('[Universal OJ] 未检测到支持的平台'); return null; } const currentPlatform = detectPlatform(); if (!currentPlatform) return; GM_addStyle(` .hljs{color:#ffffff;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c} `); GM_addStyle(` .uoj-editor-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); display: none; justify-content: center; align-items: center; z-index: 99999; } .uoj-editor-overlay.active { display: flex; } .uoj-editor-container { width: 95%; max-width: 1200px; height: 90vh; background: #1e1e2e; border: 1px solid #45475a; border-radius: 12px; display: flex; flex-direction: column; } .uoj-editor-header { padding: 14px 18px; border-bottom: 1px solid #45475a; display: flex; justify-content: space-between; align-items: center; background: #313244; border-radius: 12px 12px 0 0; } .uoj-editor-header h3 { color: #89b4fa; font-size: 15px; margin: 0; } .uoj-editor-controls { display: flex; gap: 10px; align-items: center; } .uoj-lang-select { padding: 8px 14px; border: 1px solid #45475a; border-radius: 6px; background: #1e1e2e; color: #cdd6f4; font-size: 13px; cursor: pointer; } .uoj-close-btn { width: 32px; height: 32px; border: 1px solid #45475a; border-radius: 6px; background: #313244; color: #a6adc8; font-size: 20px; cursor: pointer; } .uoj-close-btn:hover { border-color: #f38ba8; color: #f38ba8; } .uoj-editor-body { flex: 1; display: flex; overflow: hidden; padding: 15px; gap: 15px; } .uoj-problem-panel { width: 40%; background: #313244; border-radius: 8px; padding: 15px; overflow: auto; color: #cdd6f4; font-size: 13px; line-height: 1.8; } .uoj-problem-panel::-webkit-scrollbar, .uoj-code-editor::-webkit-scrollbar { width: 8px; height: 8px; } .uoj-problem-panel::-webkit-scrollbar-track, .uoj-code-editor::-webkit-scrollbar-track { background: #1e1e2e; border-radius: 4px; } .uoj-problem-panel::-webkit-scrollbar-thumb, .uoj-code-editor::-webkit-scrollbar-thumb { background: #45475a; border-radius: 4px; } .uoj-problem-panel::-webkit-scrollbar-thumb:hover, .uoj-code-editor::-webkit-scrollbar-thumb:hover { background: #585b70; } .uoj-code-panel { flex: 1; display: flex; flex-direction: column; background: #313244; border-radius: 8px; padding: 15px; } .uoj-editor-wrapper { flex: 1; display: flex; overflow: hidden; border: 1px solid #45475a; border-radius: 8px; background: #0d1117; margin-bottom: 12px; position: relative; } .uoj-line-numbers { width: 50px; background: #1e1e2e; border-right: 1px solid #45475a; padding: 12px 8px; text-align: right; color: #6c7086; overflow: hidden; flex-shrink: 0; user-select: none; line-height: 1.5 !important; font-family: 'Consolas', 'Monaco', 'Courier New', monospace !important; font-size: 14px !important; box-sizing: border-box; } .uoj-line-numbers div { line-height: 1.5 !important; height: 21px; } .uoj-code-area { flex: 1; position: relative; overflow: hidden; background: #0d1117; } .uoj-code-highlight { position: absolute; top: 0; left: 0; width: 100%; height: 100%; margin: 0; padding: 12px; background: transparent; pointer-events: none; z-index: 1; overflow: hidden; font-family: 'Consolas', 'Monaco', 'Courier New', monospace !important; font-size: 14px !important; line-height: 1.5 !important; white-space: pre; word-wrap: normal; box-sizing: border-box; } .uoj-code-highlight code { display: block; margin: 0; padding: 0; background: transparent; font-family: inherit !important; font-size: inherit !important; line-height: inherit !important; white-space: inherit; } .uoj-code-editor { position: absolute; top: 0; left: 0; width: 100%; height: 100%; margin: 0; padding: 12px; background: transparent !important; color: transparent !important; caret-color: #ffffff !important; resize: none; outline: none; z-index: 2; overflow: auto; white-space: pre; word-wrap: normal; font-family: 'Consolas', 'Monaco', 'Courier New', monospace !important; font-size: 14px !important; line-height: 1.5 !important; border: none !important; box-sizing: border-box; letter-spacing: 0; } .uoj-code-editor::selection { background: rgba(137, 180, 250, 0.3); } .uoj-editor-footer { display: flex; justify-content: space-between; align-items: center; } .uoj-editor-info { font-size: 12px; color: #a6adc8; } .uoj-btn { padding: 10px 20px; border-radius: 6px; font-size: 13px; cursor: pointer; border: none; background: #45475a; color: #cdd6f4; } .uoj-btn:hover { background: #89b4fa; color: #1e1e2e; } .uoj-open-btn { display: inline-flex !important; align-items: center; gap: 6px; padding: 10px 20px; border: 1px solid #a6e3a1; border-radius: 4px; background: transparent; color: #a6e3a1; font-size: 14px; cursor: pointer; text-decoration: none; transition: all 0.3s; margin-left: 10px; height: auto; line-height: normal; vertical-align: middle; } .uoj-open-btn:hover { background: #a6e3a1; color: #1e1e2e; border-color: #a6e3a1; } .uoj-open-btn .icon { display: flex; align-items: center; } .uoj-open-btn .text { font-weight: 500; } .uoj-open-btn-luogu { display: inline-flex !important; align-items: center; gap: 6px; padding: 8px 16px; border: 1px solid #52c41a; border-radius: 4px; background: transparent; color: #52c41a; font-size: 14px; cursor: pointer; text-decoration: none; transition: all 0.3s; margin-left: 8px; } .uoj-open-btn-luogu:hover { background: #52c41a; color: #fff; } .uoj-open-btn-luogu .icon { display: flex; align-items: center; } .uoj-open-btn-luogu .text { font-weight: 500; } .uoj-problem-panel .tex-span { font-family: 'Times New Roman', serif; font-style: italic; } .uoj-problem-panel .tex-font-style-tt { font-family: 'Courier New', monospace; background: #11111b; padding: 2px 6px; border-radius: 3px; } .cf-content-wrapper p { margin-bottom: 12px; } .cf-content-wrapper ul { padding-left: 20px; margin-bottom: 12px; } .cf-content-wrapper .tex-span { padding: 0 2px; color: #f5e0dc; } .cf-content-wrapper .tex-font-style-it { font-style: italic; } .cf-content-wrapper .tex-font-style-bf { font-weight: bold; } .cf-content-wrapper pre, .cf-content-wrapper code { white-space: pre-wrap; word-break: break-all; } .problem-statement > div:nth-child(2) { font-size: 13px; margin-bottom: 20px; } .hljs-variable-enhanced { color: #79c0ff !important; font-weight: 500 !important; } .hljs-operator-enhanced { color: #ff7b72 !important; font-weight: bold !important; } .hljs-type-enhanced { color: #ffa657 !important; font-weight: 600 !important; } .hljs-variable-enhanced { color: #79c0ff !important; font-weight: 500 !important; } .bracket-level-0 { color: #FFD700; font-weight: bold; } .bracket-level-1 { color: #DA70D6; font-weight: bold; } .bracket-level-2 { color: #87CEEB; font-weight: bold; } .bracket-level-3 { color: #98FB98; font-weight: bold; } .bracket-level-4 { color: #FFA07A; font-weight: bold; } .bracket-level-5 { color: #F0E68C; font-weight: bold; } .uoj-autocomplete { position: absolute; background: #1e1e2e; border: 1px solid #45475a; border-radius: 6px; max-height: 200px; overflow-y: auto; z-index: 10000; min-width: 150px; box-shadow: 0 4px 12px rgba(0,0,0,0.4); } .uoj-autocomplete-item { padding: 8px 12px; cursor: pointer; color: #cdd6f4; font-size: 13px; display: flex; align-items: center; gap: 8px; } .uoj-autocomplete-item:hover, .uoj-autocomplete-item.selected { background: #313244; } .uoj-autocomplete-item.selected { background: #45475a; } .uoj-autocomplete-label { flex: 1; } .uoj-autocomplete-desc { font-size: 11px; color: #6c7086; } .uoj-autocomplete::-webkit-scrollbar { width: 6px; } .uoj-autocomplete::-webkit-scrollbar-track { background: #1e1e2e; } .uoj-autocomplete::-webkit-scrollbar-thumb { background: #45475a; border-radius: 3px; } `); const codeTemplates = { c: ``, cpp: ``, go: ``, java: ``, javascript: ``, python: `` }; const langNames = { c: 'C', cpp: 'C++', go: 'Go', java: 'Java', javascript: 'JavaScript', python: 'Python 3' }; const langClasses = { c: 'language-c', cpp: 'language-cpp', go: 'language-go', java: 'language-java', javascript: 'language-javascript', python: 'language-python' }; const autoCompleteData = { cpp: { keywords: ['alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', 'bool', 'break', 'case', 'catch', 'char', 'char8_t', 'char16_t', 'char32_t', 'class', 'compl', 'concept', 'const', 'consteval', 'constexpr', 'constinit', 'const_cast', 'continue', 'co_await', 'co_return', 'co_yield', 'decltype', 'default', 'delete', 'do', 'double', 'dynamic_cast', 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'float', 'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new', 'noexcept', 'not', 'not_eq', 'nullptr', 'operator', 'or', 'or_eq', 'private', 'protected', 'public', 'register', 'reinterpret_cast', 'requires', 'return', 'short', 'signed', 'sizeof', 'static', 'static_assert', 'static_cast', 'struct', 'switch', 'template', 'this', 'thread_local', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union', 'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq'], types: ['vector', 'string', 'map', 'set', 'unordered_map', 'unordered_set', 'list', 'deque', 'queue', 'stack', 'priority_queue', 'pair', 'tuple', 'array', 'bitset', 'unique_ptr', 'shared_ptr', 'weak_ptr', 'optional', 'variant', 'any', 'function', 'bind', 'cin', 'cout', 'cerr', 'clog', 'endl', 'flush', 'ws', 'boolalpha', 'noboolalpha', 'showbase', 'noshowbase', 'showpoint', 'noshowpoint', 'showpos', 'noshowpos', 'skipws', 'noskipws', 'uppercase', 'nouppercase', 'unitbuf', 'nounitbuf', 'internal', 'left', 'right', 'dec', 'hex', 'oct', 'fixed', 'scientific', 'hexfloat', 'defaultfloat', 'make_pair', 'make_tuple', 'get', 'swap', 'move', 'forward', 'min', 'max', 'minmax', 'clamp', 'size', 'ssize', 'empty', 'data'], snippets: { 'for': 'for (int i = 0; i < n; i++) {\n \n}', 'forr': 'for (int i = n - 1; i >= 0; i--) {\n \n}', 'while': 'while () {\n \n}', 'if': 'if () {\n \n}', 'else': 'else {\n \n}', 'elif': 'else if () {\n \n}', 'main': 'int main() {\n ios::sync_with_stdio(false);\n cin.tie(nullptr);\n \n return 0;\n}', 'cout': 'cout << << endl;', 'cin': 'cin >> ;', 'vector': 'vector ', 'struct': 'struct {\n \n};', 'class': 'class {\npublic:\n \n};', 'template': 'template\n', 'using': 'using ll = long long;\nusing pii = pair;', 'pb': 'push_back', 'mp': 'make_pair', 'fi': 'first', 'se': 'second', 'sz': 'size()', 'all': 'begin(), end()', 'memset': 'memset(vis, 0, sizeof(vis));', 'gcd': '__gcd(a, b)', 'swap': 'swap(a, b);', 'sort': 'sort(begin(), end());', 'reverse': 'reverse(begin(), end());', 'unique': 'unique(begin(), end())', 'lower': 'lower_bound(begin(), end(), )', 'upper': 'upper_bound(begin(), end(), )', 'binary': 'binary_search(begin(), end(), )', 'find': 'find(begin(), end(), )', 'count': 'count(begin(), end(), )', 'accumulate': 'accumulate(begin(), end(), 0)', 'maxe': '*max_element(begin(), end())', 'mine': '*min_element(begin(), end())', 'lcm': 'lcm(a, b)', 'bit': 'bitset<32> ', 'queue': 'queue ', 'stack': 'stack ', 'pq': 'priority_queue ', 'set': 'set ', 'map': 'map ', 'umap': 'unordered_map ', 'uset': 'unordered_set ', 'deque': 'deque ', 'list': 'list ', 'array': 'array ', 'string': 'string ', 'getline': 'getline(cin, );', 'stoi': 'stoi()', 'stoll': 'stoll()', 'to_string': 'to_string()', 'substr': 'substr(,)', 'finds': 'find()', 'npos': 'string::npos', 'INF': 'const int INF = 1e9;', 'MOD': 'const int MOD = 1e9 + 7;', 'EPS': 'const double EPS = 1e-9;', 'PI': 'const double PI = acos(-1);', 'dx': 'int dx[] = {0, 1, 0, -1};', 'dy': 'int dy[] = {1, 0, -1, 0};', 'dir': 'int dx[] = {0, 1, 0, -1, 1, 1, -1, -1};\nint dy[] = {1, 0, -1, 0, 1, -1, 1, -1};', 'dfs': 'void dfs(int u) {\n vis[u] = true;\n for (int v : adj[u]) {\n if (!vis[v]) dfs(v);\n }\n}', 'bfs': 'void bfs(int s) {\n queue q;\n q.push(s);\n vis[s] = true;\n while (!q.empty()) {\n int u = q.front(); q.pop();\n for (int v : adj[u]) {\n if (!vis[v]) {\n vis[v] = true;\n q.push(v);\n }\n }\n }\n}', 'dijkstra': 'void dijkstra(int s) {\n priority_queue, greater> pq;\n dist[s] = 0;\n pq.push({0, s});\n while (!pq.empty()) {\n auto [d, u] = pq.top(); pq.pop();\n if (d > dist[u]) continue;\n for (auto [v, w] : adj[u]) {\n if (dist[u] + w < dist[v]) {\n dist[v] = dist[u] + w;\n pq.push({dist[v], v});\n }\n }\n }\n}', 'spfa': 'bool spfa(int s) {\n queue q;\n q.push(s);\n inq[s] = true;\n cnt[s] = 1;\n while (!q.empty()) {\n int u = q.front(); q.pop();\n inq[u] = false;\n for (auto [v, w] : adj[u]) {\n if (dist[u] + w < dist[v]) {\n dist[v] = dist[u] + w;\n if (!inq[v]) {\n q.push(v);\n inq[v] = true;\n if (++cnt[v] > n) return false;\n }\n }\n }\n }\n return true;\n}', 'floyd': 'for (int k = 1; k <= n; k++)\n for (int i = 1; i <= n; i++)\n for (int j = 1; j <= n; j++)\n dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);', 'kruskal': 'sort(edges.begin(), edges.end());\nint cnt = 0;\nfor (auto [w, u, v] : edges) {\n if (find(u) != find(v)) {\n unite(u, v);\n ans += w;\n if (++cnt == n - 1) break;\n }\n}', 'prim': 'priority_queue, greater> pq;\npq.push({0, 1});\nwhile (!pq.empty()) {\n auto [d, u] = pq.top(); pq.pop();\n if (vis[u]) continue;\n vis[u] = true;\n ans += d;\n for (auto [v, w] : adj[u]) {\n if (!vis[v]) pq.push({w, v});\n }\n}', 'topsort': 'queue q;\nfor (int i = 1; i <= n; i++)\n if (indeg[i] == 0) q.push(i);\nwhile (!q.empty()) {\n int u = q.front(); q.pop();\n topo.push_back(u);\n for (int v : adj[u]) {\n if (--indeg[v] == 0) q.push(v);\n }\n}', 'dsu': 'struct DSU {\n vector f;\n DSU(int n) : f(n + 1) { iota(f.begin(), f.end(), 0); }\n int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }\n void unite(int x, int y) { f[find(x)] = find(y); }\n};', 'segtree': 'struct SegTree {\n vector t;\n int n;\n SegTree(int n) : n(n), t(4 * n) {}\n void update(int o, int l, int r, int p, int v) {\n if (l == r) { t[o] = v; return; }\n int mid = (l + r) >> 1;\n if (p <= mid) update(o << 1, l, mid, p, v);\n else update(o << 1 | 1, mid + 1, r, p, v);\n t[o] = max(t[o << 1], t[o << 1 | 1]);\n }\n int query(int o, int l, int r, int L, int R) {\n if (L <= l && r <= R) return t[o];\n int mid = (l + r) >> 1, res = 0;\n if (L <= mid) res = max(res, query(o << 1, l, mid, L, R));\n if (R > mid) res = max(res, query(o << 1 | 1, mid + 1, r, L, R));\n return res;\n }\n};', 'fenwick': 'struct Fenwick {\n vector t;\n int n;\n Fenwick(int n) : n(n), t(n + 1) {}\n void add(int x, int v) {\n for (; x <= n; x += x & -x) t[x] += v;\n }\n int sum(int x) {\n int res = 0;\n for (; x; x -= x & -x) res += t[x];\n return res;\n }\n int rangeSum(int l, int r) { return sum(r) - sum(l - 1); }\n};', 'st': 'struct ST {\n vector> st;\n vector lg;\n ST(const vector& a) {\n int n = a.size();\n lg.resize(n + 1);\n for (int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;\n int k = lg[n] + 1;\n st.assign(n, vector(k));\n for (int i = 0; i < n; i++) st[i][0] = a[i];\n for (int j = 1; j < k; j++)\n for (int i = 0; i + (1 << j) <= n; i++)\n st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);\n }\n int query(int l, int r) {\n int k = lg[r - l + 1];\n return max(st[l][k], st[r - (1 << k) + 1][k]);\n }\n};', 'lca': 'int lca(int u, int v) {\n if (dep[u] < dep[v]) swap(u, v);\n for (int i = LOG - 1; i >= 0; i--)\n if (dep[u] - (1 << i) >= dep[v])\n u = fa[u][i];\n if (u == v) return u;\n for (int i = LOG - 1; i >= 0; i--)\n if (fa[u][i] != fa[v][i])\n u = fa[u][i], v = fa[v][i];\n return fa[u][0];\n}', 'kmp': 'vector getNext(const string& s) {\n int n = s.size();\n vector nxt(n);\n for (int i = 1, j = 0; i < n; i++) {\n while (j && s[i] != s[j]) j = nxt[j - 1];\n if (s[i] == s[j]) nxt[i] = ++j;\n }\n return nxt;\n}', 'manacher': 'string manacher(const string& s) {\n string t = "#";\n for (char c : s) t += c, t += "#";\n int n = t.size(), mx = 0, id = 0;\n vector p(n);\n for (int i = 0; i < n; i++) {\n p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;\n while (i - p[i] >= 0 && i + p[i] < n && t[i - p[i]] == t[i + p[i]]) p[i]++;\n if (i + p[i] > mx) mx = i + p[i], id = i;\n }\n return s.substr((id - p[id] + 1) / 2, p[id] - 1);\n}', 'trie': 'struct Trie {\n vector> tr;\n vector cnt;\n int idx;\n Trie() { tr.push_back({}); cnt.push_back(0); idx = 0; }\n void insert(const string& s) {\n int p = 0;\n for (char c : s) {\n int u = c - \'a\';\n if (!tr[p][u]) tr[p][u] = ++idx, tr.push_back({}), cnt.push_back(0);\n p = tr[p][u];\n }\n cnt[p]++;\n }\n int query(const string& s) {\n int p = 0;\n for (char c : s) {\n int u = c - \'a\';\n if (!tr[p][u]) return 0;\n p = tr[p][u];\n }\n return cnt[p];\n }\n};', 'ac': 'struct AC {\n vector> tr;\n vector fail, cnt;\n int idx;\n AC() { tr.push_back({}); fail.push_back(0); cnt.push_back(0); idx = 0; }\n void insert(const string& s) {\n int p = 0;\n for (char c : s) {\n int u = c - \'a\';\n if (!tr[p][u]) tr[p][u] = ++idx, tr.push_back({}), fail.push_back(0), cnt.push_back(0);\n p = tr[p][u];\n }\n cnt[p]++;\n }\n void build() {\n queue q;\n for (int i = 0; i < 26; i++) if (tr[0][i]) q.push(tr[0][i]);\n while (!q.empty()) {\n int u = q.front(); q.pop();\n for (int i = 0; i < 26; i++) {\n if (tr[u][i]) fail[tr[u][i]] = tr[fail[u]][i], q.push(tr[u][i]);\n else tr[u][i] = tr[fail[u]][i];\n }\n }\n }\n int query(const string& s) {\n int p = 0, res = 0;\n for (char c : s) {\n p = tr[p][c - \'a\'];\n for (int j = p; j && cnt[j] != -1; j = fail[j]) res += cnt[j], cnt[j] = -1;\n }\n return res;\n }\n};', 'sa': 'vector getSA(const string& s) {\n int n = s.size(), m = 128;\n vector sa(n), rk(n), oldrk(n), cnt(max(m, n) + 1);\n for (int i = 0; i < n; i++) cnt[rk[i] = s[i]]++;\n for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];\n for (int i = n - 1; i >= 0; i--) sa[--cnt[rk[i]]] = i;\n for (int w = 1; w < n; w <<= 1) {\n int p = 0;\n for (int i = n - w; i < n; i++) oldrk[p++] = i;\n for (int i = 0; i < n; i++) if (sa[i] >= w) oldrk[p++] = sa[i] - w;\n fill(cnt.begin(), cnt.begin() + m + 1, 0);\n for (int i = 0; i < n; i++) cnt[rk[oldrk[i]]]++;\n for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];\n for (int i = n - 1; i >= 0; i--) sa[--cnt[rk[oldrk[i]]]] = oldrk[i];\n oldrk = rk;\n rk[sa[0]] = p = 0;\n for (int i = 1; i < n; i++)\n rk[sa[i]] = (oldrk[sa[i]] == oldrk[sa[i - 1]] && oldrk[sa[i] + w] == oldrk[sa[i - 1] + w]) ? p : ++p;\n if (p == n - 1) break;\n m = p + 1;\n }\n return sa;\n}', 'ntt': 'void ntt(vector& a, bool inv) {\n int n = a.size();\n for (int i = 1, j = 0; i < n; i++) {\n int bit = n >> 1;\n for (; j & bit; bit >>= 1) j ^= bit;\n j ^= bit;\n if (i < j) swap(a[i], a[j]);\n }\n for (int len = 2; len <= n; len <<= 1) {\n int wlen = power(G, (MOD - 1) / len);\n if (inv) wlen = power(wlen, MOD - 2);\n for (int i = 0; i < n; i += len) {\n int w = 1;\n for (int j = 0; j < len / 2; j++) {\n int u = a[i + j], v = (ll)a[i + j + len / 2] * w % MOD;\n a[i + j] = (u + v) % MOD;\n a[i + j + len / 2] = (u - v + MOD) % MOD;\n w = (ll)w * wlen % MOD;\n }\n }\n }\n if (inv) {\n int n_inv = power(n, MOD - 2);\n for (int& x : a) x = (ll)x * n_inv % MOD;\n }\n}', 'exgcd': 'll exgcd(ll a, ll b, ll& x, ll& y) {\n if (b == 0) { x = 1; y = 0; return a; }\n ll d = exgcd(b, a % b, y, x);\n y -= a / b * x;\n return d;\n}', 'inv': 'll inv(ll a) { return power(a, MOD - 2); }', 'comb': 'll C(int n, int m) {\n if (m < 0 || m > n) return 0;\n return fac[n] * ifac[m] % MOD * ifac[n - m] % MOD;\n}', 'lucas': 'll lucas(ll n, ll m) {\n if (m == 0) return 1;\n return C(n % MOD, m % MOD) * lucas(n / MOD, m / MOD) % MOD;\n}', 'crt': 'll crt(const vector& r, const vector& m) {\n ll M = 1, ans = 0;\n for (ll x : m) M *= x;\n for (int i = 0; i < m.size(); i++) {\n ll Mi = M / m[i];\n ll _, ti;\n exgcd(Mi, m[i], _, ti);\n ans = (ans + r[i] * Mi * (ti % m[i] + m[i]) % m[i]) % M;\n }\n return (ans % M + M) % M;\n}', 'bsgs': 'll bsgs(ll a, ll b, ll p) {\n a %= p; b %= p;\n if (b == 1) return 0;\n if (a == 0) return b == 0 ? 1 : -1;\n ll k = sqrt(p) + 1;\n unordered_map mp;\n for (ll i = 0, t = b; i < k; i++, t = t * a % p) mp[t] = i;\n ll ak = 1;\n for (int i = 0; i < k; i++) ak = ak * a % p;\n for (ll i = 1, t = ak; i <= k; i++, t = t * ak % p)\n if (mp.count(t)) return i * k - mp[t];\n return -1;\n}', 'isprime': 'bool isPrime(ll n) {\n if (n < 2) return false;\n for (ll i = 2; i * i <= n; i++)\n if (n % i == 0) return false;\n return true;\n}', 'factor': 'vector factor(ll n) {\n vector res;\n for (ll i = 2; i * i <= n; i++) {\n while (n % i == 0) res.push_back(i), n /= i;\n }\n if (n > 1) res.push_back(n);\n return res;\n}', 'phi': 'll phi(ll n) {\n ll res = n;\n for (ll i = 2; i * i <= n; i++) {\n if (n % i == 0) {\n res = res / i * (i - 1);\n while (n % i == 0) n /= i;\n }\n }\n if (n > 1) res = res / n * (n - 1);\n return res;\n}', 'mu': 'void getMu(int n) {\n vector primes;\n vector vis(n + 1);\n mu[1] = 1;\n for (int i = 2; i <= n; i++) {\n if (!vis[i]) primes.push_back(i), mu[i] = -1;\n for (int p : primes) {\n if (i * p > n) break;\n vis[i * p] = true;\n if (i % p == 0) { mu[i * p] = 0; break; }\n mu[i * p] = -mu[i];\n }\n }\n}', 'sieve': 'vector sieve(int n) {\n vector isPrime(n + 1, true);\n isPrime[0] = isPrime[1] = false;\n for (int i = 2; i * i <= n; i++)\n if (isPrime[i])\n for (int j = i * i; j <= n; j += i)\n isPrime[j] = false;\n return isPrime;\n}', 'euler': 'void euler(int n) {\n vector primes;\n vector vis(n + 1);\n phi[1] = 1;\n for (int i = 2; i <= n; i++) {\n if (!vis[i]) primes.push_back(i), phi[i] = i - 1;\n for (int p : primes) {\n if (i * p > n) break;\n vis[i * p] = true;\n if (i % p == 0) { phi[i * p] = phi[i] * p; break; }\n phi[i * p] = phi[i] * (p - 1);\n }\n }\n}', 'quickpow': 'll power(ll a, ll b, ll mod = MOD) {\n ll res = 1;\n a %= mod;\n while (b) {\n if (b & 1) res = res * a % mod;\n a = a * a % mod;\n b >>= 1;\n }\n return res;\n}', 'read': 'template\nvoid read(T& x) {\n x = 0;\n char c = getchar();\n while (c < \'0\' || c > \'9\') c = getchar();\n while (c >= \'0\' && c <= \'9\') x = x * 10 + c - \'0\', c = getchar();\n}', 'write': 'void write(ll x) {\n if (x < 0) putchar(\'-\'), x = -x;\n if (x > 9) write(x / 10);\n putchar(x % 10 + \'0\');\n}' } }, c: { keywords: ['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'inline', 'int', 'long', 'register', 'restrict', 'return', 'short', 'signed', 'sizeof', 'static', 'struct', 'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while', '_Alignas', '_Alignof', '_Atomic', '_Bool', '_Complex', '_Generic', '_Imaginary', '_Noreturn', '_Static_assert', '_Thread_local'], types: ['NULL', 'size_t', 'FILE', 'int8_t', 'int16_t', 'int32_t', 'int64_t', 'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t', 'intptr_t', 'uintptr_t', 'true', 'false'], snippets: { 'for': 'for (int i = 0; i < n; i++) {\n \n}', 'forr': 'for (int i = n - 1; i >= 0; i--) {\n \n}', 'while': 'while () {\n \n}', 'if': 'if () {\n \n}', 'else': 'else {\n \n}', 'elif': 'else if () {\n \n}', 'main': 'int main() {\n \n return 0;\n}', 'printf': 'printf("", );', 'scanf': 'scanf("", &);', 'struct': 'struct {\n \n};', 'malloc': 'malloc(sizeof())', 'calloc': 'calloc(, sizeof())', 'realloc': 'realloc(, )', 'free': 'free();', 'memset': 'memset(, 0, sizeof());', 'memcpy': 'memcpy(, , sizeof());', 'strlen': 'strlen()', 'strcmp': 'strcmp(, )', 'strcpy': 'strcpy(, )', 'fgets': 'fgets(, , stdin);', 'fopen': 'fopen("", "r")', 'fclose': 'fclose();', 'fscanf': 'fscanf(, "", )', 'fprintf': 'fprintf(, "", )', 'qsort': 'qsort(, , sizeof(), cmp);', 'abs': 'abs()', 'max': 'max(,)', 'min': 'min(,)', 'swap': 'swap(&, &, sizeof());', 'gcd': '__gcd(,)', 'lcm': 'lcm(,)', 'sqrt': 'sqrt()', 'pow': 'pow(,)', 'log': 'log()', 'log10': 'log10()', 'exp': 'exp()', 'sin': 'sin()', 'cos': 'cos()', 'tan': 'tan()', 'asin': 'asin()', 'acos': 'acos()', 'atan': 'atan()', 'rand': 'rand()', 'srand': 'srand(time(NULL));', 'time': 'time(NULL)', 'clock': 'clock()', 'exit': 'exit(0);', 'assert': 'assert();', 'define': '#define ', 'ifdef': '#ifdef \n#endif', 'ifndef': '#ifndef \n#endif', 'include': '#include <>', 'pragma': '#pragma ', 'typedef': 'typedef ;', 'static': 'static ', 'const': 'const ', 'volatile': 'volatile ', 'extern': 'extern ', 'inline': 'inline ', 'restrict': 'restrict ' } }, java: { keywords: ['abstract', 'assert', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'default', 'do', 'double', 'else', 'enum', 'extends', 'final', 'finally', 'float', 'for', 'goto', 'if', 'implements', 'import', 'instanceof', 'int', 'interface', 'long', 'native', 'new', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'try', 'void', 'volatile', 'while', 'true', 'false', 'null', 'var', 'yield', 'record', 'sealed', 'permits', 'non-sealed'], types: ['String', 'Integer', 'Long', 'Double', 'Float', 'Boolean', 'Character', 'Byte', 'Short', 'Void', 'Object', 'Class', 'System', 'Math', 'Arrays', 'Collections', 'List', 'ArrayList', 'LinkedList', 'Vector', 'Stack', 'Queue', 'PriorityQueue', 'Deque', 'ArrayDeque', 'Set', 'HashSet', 'LinkedHashSet', 'TreeSet', 'Map', 'HashMap', 'LinkedHashMap', 'TreeMap', 'Hashtable', 'Properties', 'Iterator', 'ListIterator', 'Enumeration', 'Scanner', 'BufferedReader', 'BufferedWriter', 'FileReader', 'FileWriter', 'PrintStream', 'InputStream', 'OutputStream', 'FileInputStream', 'FileOutputStream', 'ObjectInputStream', 'ObjectOutputStream', 'ByteArrayInputStream', 'ByteArrayOutputStream', 'DataInputStream', 'DataOutputStream', 'RandomAccessFile', 'File', 'Path', 'Paths', 'Files', 'Stream', 'IntStream', 'LongStream', 'DoubleStream', 'Optional', 'OptionalInt', 'OptionalLong', 'OptionalDouble', 'CompletableFuture', 'Thread', 'Runnable', 'Callable', 'Future', 'ExecutorService', 'Executors', 'Semaphore', 'CountDownLatch', 'CyclicBarrier', 'Lock', 'ReentrantLock', 'ReadWriteLock', 'Condition', 'AtomicInteger', 'AtomicLong', 'AtomicBoolean', 'AtomicReference', 'StringBuilder', 'StringBuffer', 'Pattern', 'Matcher', 'BigInteger', 'BigDecimal', 'LocalDate', 'LocalTime', 'LocalDateTime', 'Instant', 'Duration', 'Period', 'DateTimeFormatter', 'ZoneId', 'Comparator', 'Comparable', 'Function', 'Predicate', 'Consumer', 'Supplier', 'UnaryOperator', 'BinaryOperator', 'Collector', 'Collectors'], snippets: { 'main': 'public static void main(String[] args) {\n \n}', 'class': 'public class {\n \n}', 'for': 'for (int i = 0; i < n; i++) {\n \n}', 'forr': 'for (int i = n - 1; i >= 0; i--) {\n \n}', 'foreach': 'for ( : ) {\n \n}', 'while': 'while () {\n \n}', 'if': 'if () {\n \n}', 'else': 'else {\n \n}', 'elif': 'else if () {\n \n}', 'switch': 'switch () {\n case :\n break;\n default:\n}', 'try': 'try {\n \n} catch (Exception e) {\n e.printStackTrace();\n}', 'tryf': 'try {\n \n} catch (Exception e) {\n e.printStackTrace();\n} finally {\n \n}', 'sout': 'System.out.println();', 'soutv': 'System.out.println(" = " + );', 'soutm': 'System.out.println(".");', 'scanner': 'Scanner sc = new Scanner(System.in);', 'nextint': 'sc.nextInt()', 'nextlong': 'sc.nextLong()', 'nextdouble': 'sc.nextDouble()', 'nextline': 'sc.nextLine()', 'next': 'sc.next()', 'parseint': 'Integer.parseInt()', 'parselong': 'Long.parseLong()', 'parsedouble': 'Double.parseDouble()', 'tostring': '.toString()', 'length': '.length()', 'size': '.size()', 'isempty': '.isEmpty()', 'contains': '.contains()', 'add': '.add()', 'remove': '.remove()', 'get': '.get()', 'set': '.set()', 'clear': '.clear()', 'sort': 'Collections.sort();', 'reverse': 'Collections.reverse();', 'binary': 'Collections.binarySearch();', 'max': 'Collections.max()', 'min': 'Collections.min()', 'swap': 'Collections.swap();', 'fill': 'Collections.fill();', 'copy': 'Collections.copy();', 'shuffle': 'Collections.shuffle();', 'aslist': 'Arrays.asList()', 'tolist': '.toArray(new String[0])', 'arraylist': 'ArrayList<>()', 'hashmap': 'HashMap<>()', 'hashset': 'HashSet<>()', 'linkedlist': 'LinkedList<>()', 'treemap': 'TreeMap<>()', 'treeset': 'TreeSet<>()', 'priority': 'PriorityQueue<>()', 'stack': 'Stack<>()', 'queue': 'LinkedList<>()', 'deque': 'ArrayDeque<>()', 'mapentry': 'Map.Entry<>', 'keyset': '.keySet()', 'values': '.values()', 'entryset': '.entrySet()', 'substring': '.substring()', 'indexof': '.indexOf()', 'lastindex': '.lastIndexOf()', 'replace': '.replace()', 'split': '.split()', 'trim': '.trim()', 'toupper': '.toUpperCase()', 'tolower': '.toLowerCase()', 'startswith': '.startsWith()', 'endswith': '.endsWith()', 'equals': '.equals()', 'compare': '.compareTo()', 'charat': '.charAt()', 'valueof': 'String.valueOf()', 'format': 'String.format()', 'join': 'String.join()', 'repeat': '.repeat()', 'strip': '.strip()', 'isblank': '.isBlank()', 'lines': '.lines()', 'mathabs': 'Math.abs()', 'mathmax': 'Math.max()', 'mathmin': 'Math.min()', 'mathsqrt': 'Math.sqrt()', 'mathpow': 'Math.pow()', 'mathexp': 'Math.exp()', 'mathlog': 'Math.log()', 'mathlog10': 'Math.log10()', 'mathsin': 'Math.sin()', 'mathcos': 'Math.cos()', 'mathtan': 'Math.tan()', 'mathasin': 'Math.asin()', 'mathacos': 'Math.acos()', 'mathatan': 'Math.atan()', 'mathceil': 'Math.ceil()', 'mathfloor': 'Math.floor()', 'mathround': 'Math.round()', 'mathrandom': 'Math.random()', 'mathpi': 'Math.PI', 'mathmaxint': 'Integer.MAX_VALUE', 'mathminint': 'Integer.MIN_VALUE', 'mathmaxlong': 'Long.MAX_VALUE', 'mathminlong': 'Long.MIN_VALUE', 'thread': 'new Thread(() -> {\n \n}).start();', 'runnable': 'Runnable r = () -> {\n \n};', 'synchronized': 'synchronized () {\n \n}', 'override': '@Override', 'deprecated': '@Deprecated', 'suppress': '@SuppressWarnings("")', 'functional': '@FunctionalInterface', 'safevarargs': '@SafeVarargs', 'repeatable': '@Repeatable', 'target': '@Target({})', 'retention': '@Retention(RetentionPolicy.RUNTIME)', 'documented': '@Documented', 'inherited': '@Inherited', 'native': 'native ', 'strictfp': 'strictfp ', 'transient': 'transient ', 'volatile': 'volatile ', 'assert': 'assert ;', 'this': 'this.', 'super': 'super.', 'instanceof': ' instanceof ', 'new': 'new ', 'return': 'return ;', 'break': 'break;', 'continue': 'continue;', 'throw': 'throw new Exception();', 'throws': 'throws ', 'extends': 'extends ', 'implements': 'implements ', 'package': 'package ;', 'import': 'import ;', 'public': 'public ', 'private': 'private ', 'protected': 'protected ', 'static': 'static ', 'final': 'final ', 'abstract': 'abstract ', 'interface': 'interface {\n \n}', 'enum': 'enum {\n \n}', 'record': 'record (,) {}', 'sealed': 'sealed class permits {}', 'permits': 'permits ', 'non-sealed': 'non-sealed ', 'yield': 'yield ;', 'var': 'var ', 'null': 'null', 'true': 'true', 'false': 'false' } }, python: { keywords: ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield'], types: ['list', 'dict', 'set', 'tuple', 'str', 'int', 'float', 'bool', 'bytes', 'bytearray', 'memoryview', 'range', 'frozenset', 'complex', 'object', 'type', 'enumerate', 'zip', 'map', 'filter', 'reduce', 'sum', 'min', 'max', 'abs', 'round', 'pow', 'divmod', 'len', 'sorted', 'reversed', 'any', 'all', 'chr', 'ord', 'hex', 'oct', 'bin', 'format', 'repr', 'eval', 'exec', 'compile', 'open', 'input', 'print', 'range', 'xrange', 'len', 'sorted', 'reversed', 'enumerate', 'zip', 'map', 'filter', 'sum', 'min', 'max', 'abs', 'round', 'pow', 'divmod', 'any', 'all', 'chr', 'ord', 'hex', 'oct', 'bin', 'format', 'repr', 'ascii', 'bytes', 'bytearray', 'memoryview', 'hash', 'id', 'type', 'isinstance', 'issubclass', 'callable', 'hasattr', 'getattr', 'setattr', 'delattr', 'property', 'staticmethod', 'classmethod', 'super', 'object', '__init__', '__str__', '__repr__', '__len__', '__getitem__', '__setitem__', '__delitem__', '__iter__', '__next__', '__contains__', '__call__', '__enter__', '__exit__', '__name__', '__main__', '__file__', '__doc__', '__package__', '__spec__', '__annotations__', '__builtins__', '__cached__', '__loader__', '__import__'], snippets: { 'def': 'def ():\n """"""\n pass', 'defs': 'def (self):\n """"""\n pass', 'class': 'class :\n """"""\n def __init__(self):\n pass', 'if': 'if :\n ', 'else': 'else:\n ', 'elif': 'elif :\n ', 'for': 'for in :\n ', 'while': 'while :\n ', 'try': 'try:\n \nexcept Exception as e:\n print(e)', 'tryf': 'try:\n \nexcept Exception as e:\n print(e)\nfinally:\n ', 'with': 'with as :\n ', 'lambda': 'lambda : ', 'list': '[]', 'dict': '{}', 'set': 'set()', 'tuple': '()', 'comp': '[ for in ]', 'dictc': '{: for in }', 'setc': '{ for in }', 'genc': '( for in )', 'print': 'print()', 'input': 'input()', 'int': 'int()', 'float': 'float()', 'str': 'str()', 'bool': 'bool()', 'listc': 'list()', 'dictc': 'dict()', 'setc': 'set()', 'tuplec': 'tuple()', 'range': 'range()', 'len': 'len()', 'enumerate': 'enumerate()', 'zip': 'zip()', 'map': 'map()', 'filter': 'filter()', 'reduce': 'reduce()', 'sum': 'sum()', 'min': 'min()', 'max': 'max()', 'abs': 'abs()', 'round': 'round()', 'pow': 'pow()', 'divmod': 'divmod()', 'sorted': 'sorted()', 'reversed': 'reversed()', 'any': 'any()', 'all': 'all()', 'chr': 'chr()', 'ord': 'ord()', 'hex': 'hex()', 'oct': 'oct()', 'bin': 'bin()', 'format': 'format()', 'repr': 'repr()', 'ascii': 'ascii()', 'bytes': 'bytes()', 'bytearray': 'bytearray()', 'memoryview': 'memoryview()', 'hash': 'hash()', 'id': 'id()', 'type': 'type()', 'isinstance': 'isinstance()', 'issubclass': 'issubclass()', 'callable': 'callable()', 'hasattr': 'hasattr()', 'getattr': 'getattr()', 'setattr': 'setattr()', 'delattr': 'delattr()', 'property': '@property\ndef (self):\n return ', 'staticmethod': '@staticmethod\ndef ():\n pass', 'classmethod': '@classmethod\ndef (cls):\n pass', 'abstract': '@abstractmethod\ndef (self):\n pass', 'dataclass': '@dataclass\nclass :\n : ', 'super': 'super()', 'self': 'self', 'init': 'def __init__(self):\n pass', 'strm': 'def __str__(self):\n return ""', 'reprm': 'def __repr__(self):\n return ""', 'lenm': 'def __len__(self):\n return 0', 'getitem': 'def __getitem__(self, key):\n return ', 'setitem': 'def __setitem__(self, key, value):\n pass', 'delitem': 'def __delitem__(self, key):\n pass', 'iter': 'def __iter__(self):\n return self', 'next': 'def __next__(self):\n raise StopIteration', 'contains': 'def __contains__(self, item):\n return False', 'call': 'def __call__(self, *args, **kwargs):\n return ', 'enter': 'def __enter__(self):\n return self', 'exit': 'def __exit__(self, exc_type, exc_val, exc_tb):\n pass', 'import': 'import ', 'from': 'from import ', 'as': ' as ', 'global': 'global ', 'nonlocal': 'nonlocal ', 'assert': 'assert ', 'raise': 'raise ', 'yield': 'yield ', 'return': 'return ', 'pass': 'pass', 'break': 'break', 'continue': 'continue', 'del': 'del ', 'in': ' in ', 'is': ' is ', 'not': 'not ', 'and': ' and ', 'or': ' or ', 'True': 'True', 'False': 'False', 'None': 'None', 'append': '.append()', 'extend': '.extend()', 'insert': '.insert()', 'remove': '.remove()', 'pop': '.pop()', 'clear': '.clear()', 'index': '.index()', 'count': '.count()', 'sort': '.sort()', 'reverse': '.reverse()', 'copy': '.copy()', 'keys': '.keys()', 'values': '.values()', 'items': '.items()', 'get': '.get()', 'update': '.update()', 'setdefault': '.setdefault()', 'popitem': '.popitem()', 'join': '.join()', 'split': '.split()', 'strip': '.strip()', 'lstrip': '.lstrip()', 'rstrip': '.rstrip()', 'replace': '.replace()', 'find': '.find()', 'rfind': '.rfind()', 'indexof': '.index()', 'rindex': '.rindex()', 'startswith': '.startswith()', 'endswith': '.endswith()', 'upper': '.upper()', 'lower': '.lower()', 'capitalize': '.capitalize()', 'title': '.title()', 'swapcase': '.swapcase()', 'center': '.center()', 'ljust': '.ljust()', 'rjust': '.rjust()', 'zfill': '.zfill()', 'expandtabs': '.expandtabs()', 'encode': '.encode()', 'decode': '.decode()', 'format': '.format()', 'startswith': '.startswith()', 'endswith': '.endswith()', 'isalnum': '.isalnum()', 'isalpha': '.isalpha()', 'isascii': '.isascii()', 'isdecimal': '.isdecimal()', 'isdigit': '.isdigit()', 'isidentifier': '.isidentifier()', 'islower': '.islower()', 'isnumeric': '.isnumeric()', 'isprintable': '.isprintable()', 'isspace': '.isspace()', 'istitle': '.istitle()', 'isupper': '.isupper()', 'open': 'open()', 'read': '.read()', 'write': '.write()', 'readline': '.readline()', 'readlines': '.readlines()', 'writelines': '.writelines()', 'close': '.close()', 'seek': '.seek()', 'tell': '.tell()', 'flush': '.flush()', 'truncate': '.truncate()', 'fileno': '.fileno()', 'isatty': '.isatty()', 'readable': '.readable()', 'writable': '.writable()', 'seekable': '.seekable()', 'json': 'import json\njson.dumps()', 'pickle': 'import pickle\npickle.dumps()', 're': 'import re\nre.match()', 'sys': 'import sys\nsys.exit()', 'os': 'import os\nos.path.join()', 'math': 'import math\nmath.sqrt()', 'random': 'import random\nrandom.randint()', 'datetime': 'import datetime\ndatetime.now()', 'time': 'import time\ntime.time()', 'collections': 'from collections import deque, Counter, defaultdict', 'itertools': 'from itertools import permutations, combinations, product', 'functools': 'from functools import lru_cache, reduce, cmp_to_key', 'heapq': 'import heapq\nheapq.heappush()', 'bisect': 'import bisect\nbisect.bisect_left()', 'copy': 'import copy\ncopy.deepcopy()', 'decimal': 'from decimal import Decimal, getcontext', 'fractions': 'from fractions import Fraction', 'statistics': 'import statistics\nstatistics.mean()', 'typing': 'from typing import List, Dict, Set, Tuple, Optional, Union', 'numpy': 'import numpy as np', 'pandas': 'import pandas as pd', 'matplotlib': 'import matplotlib.pyplot as plt', 'requests': 'import requests\nrequests.get()', 'bs4': 'from bs4 import BeautifulSoup', 'sqlite3': 'import sqlite3\nconn = sqlite3.connect()', 'threading': 'import threading\nthread = threading.Thread()', 'multiprocessing': 'from multiprocessing import Pool', 'asyncio': 'import asyncio\nasync def main():\n pass', 'aiohttp': 'import aiohttp\nasync with aiohttp.ClientSession() as session:', 'flask': 'from flask import Flask\napp = Flask(__name__)', 'django': 'from django.shortcuts import render', 'fastapi': 'from fastapi import FastAPI\napp = FastAPI()', 'pytest': 'import pytest\n@pytest.mark.parametrize', 'unittest': 'import unittest\nclass Test(unittest.TestCase):', 'mock': 'from unittest.mock import Mock, patch', 'logging': 'import logging\nlogging.basicConfig()', 'argparse': 'import argparse\nparser = argparse.ArgumentParser()', 'configparser': 'import configparser\nconfig = configparser.ConfigParser()', 'pathlib': 'from pathlib import Path\npath = Path()', 'shutil': 'import shutil\nshutil.copy()', 'glob': 'import glob\nglob.glob()', 'fnmatch': 'import fnmatch\nfnmatch.fnmatch()', 'tempfile': 'import tempfile\nwith tempfile.TemporaryFile() as f:', 'hashlib': 'import hashlib\nhashlib.md5()', 'base64': 'import base64\nbase64.b64encode()', 'urllib': 'import urllib.request\nurllib.request.urlopen()', 'http': 'import http.client\nconn = http.client.HTTPConnection()', 'socket': 'import socket\ns = socket.socket()', 'subprocess': 'import subprocess\nsubprocess.run()', 'signal': 'import signal\nsignal.signal()', 'atexit': 'import atexit\n@atexit.register', 'weakref': 'import weakref\nweakref.ref()', 'gc': 'import gc\ngc.collect()', 'inspect': 'import inspect\ninspect.getmembers()', 'ast': 'import ast\nast.parse()', 'dis': 'import dis\ndis.dis()', 'pdb': 'import pdb\npdb.set_trace()', 'traceback': 'import traceback\ntraceback.print_exc()', 'warnings': 'import warnings\nwarnings.warn()', 'contextlib': 'from contextlib import contextmanager\n@contextmanager', 'functools': 'from functools import wraps\n@wraps', 'total_ordering': '@functools.total_ordering', 'singledispatch': '@functools.singledispatch', 'lru_cache': '@functools.lru_cache(maxsize=128)', 'cache': '@functools.cache', 'cmp_to_key': 'functools.cmp_to_key()', 'partial': 'functools.partial()', 'reduce': 'functools.reduce()' } }, go: { keywords: ['break', 'case', 'chan', 'const', 'continue', 'default', 'defer', 'else', 'fallthrough', 'for', 'func', 'go', 'goto', 'if', 'import', 'interface', 'map', 'package', 'range', 'return', 'select', 'struct', 'switch', 'type', 'var'], types: ['bool', 'byte', 'complex64', 'complex128', 'error', 'float32', 'float64', 'int', 'int8', 'int16', 'int32', 'int64', 'rune', 'string', 'uint', 'uint8', 'uint16', 'uint32', 'uint64', 'uintptr', 'any', 'comparable', 'true', 'false', 'iota', 'nil', 'append', 'cap', 'close', 'complex', 'copy', 'delete', 'imag', 'len', 'make', 'new', 'panic', 'print', 'println', 'real', 'recover'], snippets: { 'package': 'package main', 'import': 'import (\n \n)', 'func': 'func () {\n \n}', 'main': 'func main() {\n \n}', 'for': 'for i := 0; i < n; i++ {\n \n}', 'forr': 'for i := n - 1; i >= 0; i-- {\n \n}', 'range': 'for _, v := range {\n \n}', 'rangei': 'for i, v := range {\n \n}', 'if': 'if {\n \n}', 'else': 'else {\n \n}', 'elif': 'else if {\n \n}', 'switch': 'switch {\n case :\n \n default:\n \n}', 'select': 'select {\n case <-:\n \n default:\n \n}', 'struct': 'type struct {\n \n}', 'interface': 'type interface {\n \n}', 'type': 'type ', 'const': 'const = ', 'var': 'var ', ':=': ' := ', 'make': 'make()', 'new': 'new()', 'append': 'append(,)', 'len': 'len()', 'cap': 'cap()', 'copy': 'copy(,)', 'delete': 'delete(,)', 'close': 'close()', 'panic': 'panic()', 'recover': 'recover()', 'print': 'print()', 'println': 'println()', 'fmt': 'fmt.Printf("", )', 'fmtln': 'fmt.Println()', 'scan': 'fmt.Scan(&)', 'scanf': 'fmt.Scanf("", )', 'sprintf': 'fmt.Sprintf("", )', 'error': 'errors.New("")', 'nil': 'nil', 'true': 'true', 'false': 'false', 'iota': 'iota', 'int': 'int', 'int8': 'int8', 'int16': 'int16', 'int32': 'int32', 'int64': 'int64', 'uint': 'uint', 'uint8': 'uint8', 'uint16': 'uint16', 'uint32': 'uint32', 'uint64': 'uint64', 'float32': 'float32', 'float64': 'float64', 'complex64': 'complex64', 'complex128': 'complex128', 'byte': 'byte', 'rune': 'rune', 'string': 'string', 'bool': 'bool', 'any': 'any', 'comparable': 'comparable', 'uintptr': 'uintptr', 'chan': 'chan ', 'goroutine': 'go func() {\n \n}()', 'defer': 'defer func() {\n \n}()', 'return': 'return ', 'break': 'break', 'continue': 'continue', 'fallthrough': 'fallthrough', 'goto': 'goto ', 'map': 'map[]', 'slice': '[]', 'array': '[]', 'pointer': '*', 'address': '&', 'channel': 'make(chan )', 'buffered': 'make(chan , )', 'goroutine': 'go ', 'waitgroup': 'var wg sync.WaitGroup\nwg.Add()\nwg.Wait()', 'mutex': 'var mu sync.Mutex\nmu.Lock()\ndefer mu.Unlock()', 'rwmutex': 'var rw sync.RWMutex\nrw.RLock()\ndefer rw.RUnlock()', 'once': 'var once sync.Once\nonce.Do(func() {\n \n})', 'pool': 'var pool = sync.Pool{\n New: func() interface{} {\n return nil\n },\n}', 'context': 'ctx, cancel := context.WithCancel(context.Background())\ndefer cancel()', 'timeout': 'ctx, cancel := context.WithTimeout(context.Background(), time.Second)\ndefer cancel()', 'deadline': 'ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second))\ndefer cancel()', 'value': 'ctx := context.WithValue(context.Background(), key, value)', 'timer': 'timer := time.NewTimer(time.Second)\n<-timer.C', 'ticker': 'ticker := time.NewTicker(time.Second)\nfor range ticker.C {\n \n}', 'sleep': 'time.Sleep(time.Second)', 'after': '<-time.After(time.Second)', 'tick': '<-time.Tick(time.Second)', 'now': 'time.Now()', 'since': 'time.Since()', 'until': 'time.Until()', 'format': '.Format(time.RFC3339)', 'parse': 'time.Parse(time.RFC3339, )', 'duration': 'time.Duration()', 'second': 'time.Second', 'minute': 'time.Minute', 'hour': 'time.Hour', 'millisecond': 'time.Millisecond', 'microsecond': 'time.Microsecond', 'nanosecond': 'time.Nanosecond', 'json': 'json.Marshal()', 'jsoni': 'json.Unmarshal()', 'xml': 'xml.Marshal()', 'xmli': 'xml.Unmarshal()', 'yaml': 'yaml.Marshal()', 'ymli': 'yaml.Unmarshal()', 'csv': 'csv.NewReader()', 'zip': 'zip.NewReader()', 'tar': 'tar.NewReader()', 'gzip': 'gzip.NewReader()', 'http': 'http.Get()', 'httppost': 'http.Post()', 'httpnew': 'http.NewRequest()', 'serve': 'http.ListenAndServe(":8080", nil)', 'handler': 'func(w http.ResponseWriter, r *http.Request) {\n \n}', 'fileserver': 'http.FileServer(http.Dir(""))', 'template': 'template.ParseFiles()', 'execute': 'template.Execute()', 'db': 'db, err := sql.Open("", "")', 'query': 'rows, err := db.Query()', 'exec': 'result, err := db.Exec()', 'prepare': 'stmt, err := db.Prepare()', 'begin': 'tx, err := db.Begin()', 'commit': 'tx.Commit()', 'rollback': 'tx.Rollback()', 'scan': 'rows.Scan()', 'next': 'rows.Next()', 'close': '.Close()', 'err': 'if err != nil {\n log.Fatal(err)\n}', 'ok': 'if !ok {\n \n}', 'exists': 'if _, ok := ; ok {\n \n}', 'regex': 'regexp.MustCompile()', 'match': '.MatchString()', 'find': '.FindString()', 'replace': '.ReplaceAllString()', 'split': '.Split()', 'strings': 'strings.Contains()', 'strconv': 'strconv.Atoi()', 'sort': 'sort.Ints()', 'reverse': 'sort.Sort(sort.Reverse())', 'search': 'sort.Search()', 'heap': 'heap.Push()', 'list': 'list.New()', 'ring': 'ring.New()', 'container': 'container/heap', 'crypto': 'crypto/sha256', 'hash': 'h := sha256.New()', 'rand': 'rand.Intn()', 'crypto': 'crypto/rand', 'big': 'big.NewInt()', 'rat': 'big.NewRat()', 'float': 'big.NewFloat()', 'complex': 'cmplx.Sqrt()', 'math': 'math.Sqrt()', 'abs': 'math.Abs()', 'pow': 'math.Pow()', 'max': 'math.Max()', 'min': 'math.Min()', 'ceil': 'math.Ceil()', 'floor': 'math.Floor()', 'round': 'math.Round()', 'trunc': 'math.Trunc()', 'mod': 'math.Mod()', 'sin': 'math.Sin()', 'cos': 'math.Cos()', 'tan': 'math.Tan()', 'asin': 'math.Asin()', 'acos': 'math.Acos()', 'atan': 'math.Atan()', 'atan2': 'math.Atan2()', 'exp': 'math.Exp()', 'log': 'math.Log()', 'log10': 'math.Log10()', 'log2': 'math.Log2()', 'sqrt': 'math.Sqrt()', 'cbrt': 'math.Cbrt()', 'pi': 'math.Pi', 'e': 'math.E', 'phi': 'math.Phi', 'inf': 'math.Inf(1)', 'nan': 'math.NaN()', 'isnan': 'math.IsNaN()', 'isinf': 'math.IsInf()', 'signbit': 'math.Signbit()', 'copysign': 'math.Copysign()', 'dim': 'math.Dim()', 'hypot': 'math.Hypot()', 'remainder': 'math.Remainder()', 'nextafter': 'math.Nextafter()', 'gamma': 'math.Gamma()', 'lgamma': 'math.Lgamma()', 'j0': 'math.J0()', 'j1': 'math.J1()', 'jn': 'math.Jn()', 'y0': 'math.Y0()', 'y1': 'math.Y1()', 'yn': 'math.Yn()', 'erfc': 'math.Erfc()', 'erf': 'math.Erf()', 'erfinv': 'math.Erfinv()', 'erfcinv': 'math.Erfcinv()', 'norm': 'math.Norm()', 'norminv': 'math.Norminv()', 'pow10': 'math.Pow10()', 'ilogb': 'math.Ilogb()', 'logb': 'math.Logb()', 'frexp': 'math.Frexp()', 'ldexp': 'math.Ldexp()', 'modf': 'math.Modf()', 'sincos': 'math.Sincos()', 'sincosh': 'math.Sincosh()', 'tanh': 'math.Tanh()', 'sinh': 'math.Sinh()', 'cosh': 'math.Cosh()', 'asinh': 'math.Asinh()', 'acosh': 'math.Acosh()', 'atanh': 'math.Atanh()', 'expm1': 'math.Expm1()', 'log1p': 'math.Log1p()', 'fma': 'math.FMA()', 'float32bits': 'math.Float32bits()', 'float32frombits': 'math.Float32frombits()', 'float64bits': 'math.Float64bits()', 'float64frombits': 'math.Float64frombits()', 'abs32': 'math.Abs(32)', 'abs64': 'math.Abs(64)', 'max32': 'math.Max(32)', 'max64': 'math.Max(64)', 'min32': 'math.Min(32)', 'min64': 'math.Min(64)' } }, javascript: { keywords: ['await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'export', 'extends', 'finally', 'for', 'function', 'if', 'import', 'in', 'instanceof', 'new', 'return', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield', 'let', 'static', 'yield', 'await', 'of'], types: ['console', 'Array', 'Object', 'String', 'Number', 'Boolean', 'Date', 'RegExp', 'Function', 'Math', 'JSON', 'Promise', 'Set', 'Map', 'WeakSet', 'WeakMap', 'Symbol', 'BigInt', 'Error', 'EvalError', 'RangeError', 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError', 'ArrayBuffer', 'SharedArrayBuffer', 'DataView', 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array', 'Intl', 'Collator', 'DateTimeFormat', 'ListFormat', 'NumberFormat', 'PluralRules', 'RelativeTimeFormat', 'Segmenter', 'document', 'window', 'navigator', 'location', 'history', 'localStorage', 'sessionStorage', 'fetch', 'XMLHttpRequest', 'WebSocket', 'EventSource', 'Worker', 'SharedWorker', 'Atomics', 'WebAssembly', 'Buffer', 'process', 'global', 'require', 'module', 'exports', '__dirname', '__filename', 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval', 'setImmediate', 'clearImmediate', 'queueMicrotask', 'performance', 'crypto', 'TextEncoder', 'TextDecoder', 'URL', 'URLSearchParams', 'FormData', 'Headers', 'Request', 'Response', 'Blob', 'File', 'FileReader', 'FileList', 'DragEvent', 'ClipboardEvent', 'CustomEvent', 'MutationObserver', 'IntersectionObserver', 'ResizeObserver', 'PerformanceObserver', 'ReportingObserver', 'Notification', 'PermissionStatus', 'PushManager', 'PushSubscription', 'ServiceWorker', 'ServiceWorkerRegistration', 'ServiceWorkerContainer', 'Cache', 'CacheStorage', 'Clients', 'Client', 'WindowClient', 'BackgroundFetchManager', 'BackgroundFetchRecord', 'BackgroundFetchRegistration', 'SyncManager', 'SyncEvent', 'PeriodicSyncManager', 'PeriodicSyncEvent', 'PushEvent', 'NotificationEvent', 'ExtendableEvent', 'ExtendableMessageEvent', 'FetchEvent', 'InstallEvent', 'ActivateEvent', 'MessageEvent', 'ErrorEvent', 'CloseEvent', 'PromiseRejectionEvent', 'UnhandledRejectionEvent', 'RejectionHandledEvent', 'PopStateEvent', 'HashChangeEvent', 'PageTransitionEvent', 'BeforeUnloadEvent', 'UnloadEvent', 'LoadEvent', 'DOMContentLoadedEvent', 'ReadystatechangeEvent', 'ScrollEvent', 'ResizeEvent', 'FocusEvent', 'BlurEvent', 'FocusinEvent', 'FocusoutEvent', 'InputEvent', 'ChangeEvent', 'SubmitEvent', 'ResetEvent', 'ClickEvent', 'DblclickEvent', 'MousedownEvent', 'MouseupEvent', 'MousemoveEvent', 'MouseoverEvent', 'MouseoutEvent', 'MouseenterEvent', 'MouseleaveEvent', 'ContextmenuEvent', 'WheelEvent', 'KeydownEvent', 'KeyupEvent', 'KeypressEvent', 'TouchEvent', 'PointerEvent', 'GestureEvent', 'CompositionEvent', 'BeforeInputEvent', 'InvalidEvent', 'SearchEvent', 'SelectEvent', 'ToggleEvent', 'ShowEvent', 'HideEvent', 'OpenEvent', 'CloseEvent', 'CancelEvent', 'PlayEvent', 'PauseEvent', 'EndedEvent', 'LoadedmetadataEvent', 'LoadeddataEvent', 'CanplayEvent', 'CanplaythroughEvent', 'WaitingEvent', 'PlayingEvent', 'SeekingEvent', 'SeekedEvent', 'TimeupdateEvent', 'VolumechangeEvent', 'RatechangeEvent', 'DurationchangeEvent', 'ProgressEvent', 'SuspendEvent', 'EmptiedEvent', 'StalledEvent', 'LoadstartEvent', 'LoadEvent', 'AbortEvent', 'ErrorEvent', 'OnlineEvent', 'OfflineEvent', 'MessageEvent', 'StorageEvent', 'HashchangeEvent', 'PopstateEvent', 'PageshowEvent', 'PagehideEvent', 'BeforeprintEvent', 'AfterprintEvent', 'AnimationEvent', 'TransitionEvent', 'AnimationstartEvent', 'AnimationendEvent', 'AnimationiterationEvent', 'TransitionstartEvent', 'TransitionendEvent', 'WebkitAnimationEvent', 'WebkitTransitionEvent', 'DOMActivateEvent', 'DOMFocusInEvent', 'DOMFocusOutEvent', 'DOMMouseScrollEvent', 'DOMSubtreeModifiedEvent', 'DOMNodeInsertedEvent', 'DOMNodeRemovedEvent', 'DOMNodeInsertedIntoDocumentEvent', 'DOMNodeRemovedFromDocumentEvent', 'DOMAttrModifiedEvent', 'DOMCharacterDataModifiedEvent', 'DOMElementNameChangedEvent', 'DOMAttributeNameChangedEvent', 'DOMContentLoadedEvent'], snippets: { 'log': 'console.log();', 'error': 'console.error();', 'warn': 'console.warn();', 'info': 'console.info();', 'debug': 'console.debug();', 'table': 'console.table();', 'time': 'console.time();', 'timee': 'console.timeEnd();', 'group': 'console.group();', 'groupc': 'console.groupCollapsed();', 'grouped': 'console.groupEnd();', 'count': 'console.count();', 'countr': 'console.countReset();', 'trace': 'console.trace();', 'assert': 'console.assert();', 'clear': 'console.clear();', 'dir': 'console.dir();', 'dirxml': 'console.dirxml();', 'profile': 'console.profile();', 'profilee': 'console.profileEnd();', 'func': 'function () {\n \n}', 'arrow': '() => {\n \n}', 'af': 'async () => {\n \n}', 'for': 'for (let i = 0; i < ; i++) {\n \n}', 'forr': 'for (let i = - 1; i >= 0; i--) {\n \n}', 'forof': 'for (const of ) {\n \n}', 'forin': 'for (const in ) {\n \n}', 'while': 'while () {\n \n}', 'dowhile': 'do {\n \n} while ();', 'if': 'if () {\n \n}', 'else': 'else {\n \n}', 'elif': 'else if () {\n \n}', 'switch': 'switch () {\n case :\n break;\n default:\n}', 'try': 'try {\n \n} catch (error) {\n console.error(error);\n}', 'tryf': 'try {\n \n} catch (error) {\n console.error(error);\n} finally {\n \n}', 'class': 'class {\n constructor() {\n \n }\n}', 'extends': 'class extends {\n constructor() {\n super();\n \n }\n}', 'import': 'import from \'\';', 'export': 'export default ;', 'named': 'export { };', 'require': 'const = require(\'\');', 'module': 'module.exports = ;', 'promise': 'new Promise((resolve, reject) => {\n \n})', 'then': '.then(() => {\n \n})', 'catch': '.catch((error) => {\n console.error(error);\n})', 'finally': '.finally(() => {\n \n})', 'async': 'async function () {\n \n}', 'await': 'await ', 'fetch': 'fetch(\'\')\n .then(response => response.json())\n .then(data => console.log(data))\n .catch(error => console.error(error));', 'axios': 'axios.get(\'\')\n .then(response => console.log(response.data))\n .catch(error => console.error(error));', 'timeout': 'setTimeout(() => {\n \n}, 1000);', 'interval': 'setInterval(() => {\n \n}, 1000);', 'immediate': 'setImmediate(() => {\n \n});', 'map': '.map(() => )', 'filter': '.filter(() => )', 'reduce': '.reduce((acc, curr) => , 0)', 'foreach': '.forEach(() => )', 'find': '.find(() => )', 'findi': '.findIndex(() => )', 'some': '.some(() => )', 'every': '.every(() => )', 'includes': '.includes()', 'indexof': '.indexOf()', 'lastindex': '.lastIndexOf()', 'slice': '.slice()', 'splice': '.splice()', 'concat': '.concat()', 'join': '.join()', 'split': '.split()', 'replace': '.replace()', 'match': '.match()', 'search': '.search()', 'trim': '.trim()', 'tolower': '.toLowerCase()', 'toupper': '.toUpperCase()', 'substr': '.substring()', 'charat': '.charAt()', 'charcode': '.charCodeAt()', 'fromchar': 'String.fromCharCode()', 'parseint': 'parseInt()', 'parsefloat': 'parseFloat()', 'isnan': 'isNaN()', 'isfinite': 'isFinite()', 'json': 'JSON.stringify()', 'jsonp': 'JSON.parse()', 'local': 'localStorage.getItem(\'\')', 'locals': 'localStorage.setItem(\'\', \'\')', 'session': 'sessionStorage.getItem(\'\')', 'sessions': 'sessionStorage.setItem(\'\', \'\')', 'query': 'document.querySelector()', 'querya': 'document.querySelectorAll()', 'getid': 'document.getElementById()', 'getclass': 'document.getElementsByClassName()', 'gettag': 'document.getElementsByTagName()', 'create': 'document.createElement()', 'append': '.appendChild()', 'remove': '.removeChild()', 'replace': '.replaceChild()', 'insert': '.insertBefore()', 'clone': '.cloneNode()', 'addevent': '.addEventListener()', 'removeevent': '.removeEventListener()', 'prevent': 'event.preventDefault()', 'stop': 'event.stopPropagation()', 'target': 'event.target', 'current': 'event.currentTarget', 'delegate': 'event.delegateTarget', 'stopimmediate': 'event.stopImmediatePropagation()', 'composed': 'event.composedPath()', 'math': 'Math.', 'abs': 'Math.abs()', 'ceil': 'Math.ceil()', 'floor': 'Math.floor()', 'round': 'Math.round()', 'max': 'Math.max()', 'min': 'Math.min()', 'pow': 'Math.pow()', 'sqrt': 'Math.sqrt()', 'cbrt': 'Math.cbrt()', 'exp': 'Math.exp()', 'log': 'Math.log()', 'log10': 'Math.log10()', 'log2': 'Math.log2()', 'sin': 'Math.sin()', 'cos': 'Math.cos()', 'tan': 'Math.tan()', 'asin': 'Math.asin()', 'acos': 'Math.acos()', 'atan': 'Math.atan()', 'atan2': 'Math.atan2()', 'random': 'Math.random()', 'pi': 'Math.PI', 'e': 'Math.E', 'ln2': 'Math.LN2', 'ln10': 'Math.LN10', 'log2e': 'Math.LOG2E', 'log10e': 'Math.LOG10E', 'sqrt1_2': 'Math.SQRT1_2', 'sqrt2': 'Math.SQRT2', 'date': 'new Date()', 'now': 'Date.now()', 'parse': 'Date.parse()', 'utc': 'Date.UTC()', 'gettime': '.getTime()', 'getfull': '.getFullYear()', 'getmonth': '.getMonth()', 'getdate': '.getDate()', 'getday': '.getDay()', 'gethours': '.getHours()', 'getmin': '.getMinutes()', 'getsec': '.getSeconds()', 'getms': '.getMilliseconds()', 'settime': '.setTime()', 'setfull': '.setFullYear()', 'setmonth': '.setMonth()', 'setdate': '.setDate()', 'sethours': '.setHours()', 'setmin': '.setMinutes()', 'setsec': '.setSeconds()', 'setms': '.setMilliseconds()', 'toiso': '.toISOString()', 'toutc': '.toUTCString()', 'tostring': '.toString()', 'tolocale': '.toLocaleString()', 'tolocaledate': '.toLocaleDateString()', 'tolocaletime': '.toLocaleTimeString()', 'reg': '/pattern/flags', 'test': '.test()', 'exec': '.exec()', 'match': '.match()', 'matchall': '.matchAll()', 'search': '.search()', 'replace': '.replace()', 'replaceall': '.replaceAll()', 'split': '.split()', 'set': 'new Set()', 'mapo': 'new Map()', 'weakset': 'new WeakSet()', 'weakmap': 'new WeakMap()', 'array': 'new Array()', 'object': 'new Object()', 'string': 'new String()', 'number': 'new Number()', 'boolean': 'new Boolean()', 'date': 'new Date()', 'regexp': 'new RegExp()', 'error': 'new Error()', 'typeerror': 'new TypeError()', 'syntaxerror': 'new SyntaxError()', 'referenceerror': 'new ReferenceError()', 'rangeerror': 'new RangeError()', 'evalerror': 'new EvalError()', 'urierror': 'new URIError()', 'aggregateerror': 'new AggregateError()', 'intl': 'new Intl.Collator()', 'bigint': 'BigInt()', 'symbol': 'Symbol()', 'proxy': 'new Proxy(target, handler)', 'reflect': 'Reflect.', 'objecta': 'Object.assign()', 'objectc': 'Object.create()', 'objectd': 'Object.defineProperty()', 'objecte': 'Object.entries()', 'objectf': 'Object.freeze()', 'objectg': 'Object.getOwnPropertyDescriptor()', 'objecth': 'Object.getOwnPropertyNames()', 'objecti': 'Object.getOwnPropertySymbols()', 'objectj': 'Object.getPrototypeOf()', 'objectk': 'Object.is()', 'objectl': 'Object.isExtensible()', 'objectm': 'Object.isFrozen()', 'objectn': 'Object.isSealed()', 'objecto': 'Object.keys()', 'objectp': 'Object.preventExtensions()', 'objectq': 'Object.seal()', 'objectr': 'Object.setPrototypeOf()', 'objects': 'Object.values()', 'arrayf': 'Array.from()', 'arrayi': 'Array.isArray()', 'arrayo': 'Array.of()', 'stringf': 'String.fromCharCode()', 'stringr': 'String.raw()', 'numberi': 'Number.isInteger()', 'numberf': 'Number.isFinite()', 'numbern': 'Number.isNaN()', 'numbers': 'Number.parseFloat()', 'numberp': 'Number.parseInt()', 'maths': 'Math.sign()', 'matht': 'Math.trunc()', 'mathf': 'Math.fround()', 'mathc': 'Math.clz32()', 'mathi': 'Math.imul()', 'jsons': 'JSON.stringify()', 'jsonp': 'JSON.parse()', 'datep': 'Date.parse()', 'dateu': 'Date.UTC()', 'regexpf': 'RegExp.prototype', 'errorp': 'Error.prototype', 'evalp': 'EvalError.prototype', 'rangep': 'RangeError.prototype', 'refp': 'ReferenceError.prototype', 'syntaxp': 'SyntaxError.prototype', 'typep': 'TypeError.prototype', 'urip': 'URIError.prototype', 'objectp': 'Object.prototype', 'arrayp': 'Array.prototype', 'stringp': 'String.prototype', 'numberp': 'Number.prototype', 'booleanp': 'Boolean.prototype', 'datep': 'Date.prototype', 'regexpf': 'RegExp.prototype', 'errorp': 'Error.prototype', 'functionp': 'Function.prototype', 'promisee': 'Promise.prototype', 'setp': 'Set.prototype', 'mapp': 'Map.prototype', 'weaksetp': 'WeakSet.prototype', 'weakmapp': 'WeakMap.prototype', 'arraybufferp': 'ArrayBuffer.prototype', 'sharedarraybufferp': 'SharedArrayBuffer.prototype', 'dataviewp': 'DataView.prototype', 'int8arrayp': 'Int8Array.prototype', 'uint8arrayp': 'Uint8Array.prototype', 'uint8clampedarrayp': 'Uint8ClampedArray.prototype', 'int16arrayp': 'Int16Array.prototype', 'uint16arrayp': 'Uint16Array.prototype', 'int32arrayp': 'Int32Array.prototype', 'uint32arrayp': 'Uint32Array.prototype', 'float32arrayp': 'Float32Array.prototype', 'float64arrayp': 'Float64Array.prototype', 'bigint64arrayp': 'BigInt64Array.prototype', 'biguint64arrayp': 'BigUint64Array.prototype', 'generatorp': 'Generator.prototype', 'asyncfunctionp': 'AsyncFunction.prototype', 'asyncgeneratorp': 'AsyncGenerator.prototype', 'intl': 'Intl.', 'collator': 'new Intl.Collator()', 'datetimeformat': 'new Intl.DateTimeFormat()', 'listformat': 'new Intl.ListFormat()', 'numberformat': 'new Intl.NumberFormat()', 'pluralrules': 'new Intl.PluralRules()', 'relativetimeformat': 'new Intl.RelativeTimeFormat()', 'segmenter': 'new Intl.Segmenter()', 'displaynames': 'new Intl.DisplayNames()', 'locale': 'new Intl.Locale()', 'getcanonical': 'Intl.getCanonicalLocales()', 'supported': 'Intl.supportedValuesOf()' } } }; let currentLang = 'cpp'; let problemId = null; function escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function createLightbox() { if (document.getElementById('uojEditorOverlay')) return; const div = document.createElement('div'); div.className = 'uoj-editor-overlay'; div.id = 'uojEditorOverlay'; div.innerHTML = `

✏️ 代码编辑器 - ${currentPlatform.name}

1
`; document.body.appendChild(div); div.addEventListener('click', (e) => { if (e.target.dataset.action === 'close' || e.target === div) { closeEditor(); } }); document.getElementById('uojLangSelect').addEventListener('change', changeLanguage); document.getElementById('uojConfirmBtn').addEventListener('click', handleConfirm); const editor = document.getElementById('uojCodeEditor'); editor.addEventListener('input', () => { updateCode(); syncScroll(); setTimeout(triggerAutocomplete, 0); }); editor.addEventListener('scroll', syncScroll); editor.addEventListener('keydown', handleKey); editor.addEventListener('click', () => { updateCursorInfo(); hideAutocomplete(); }); editor.addEventListener('keyup', (e) => { updateCursorInfo(); if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Enter', 'Tab', 'Escape', 'Shift', 'Control', 'Alt', 'Meta'].includes(e.key)) { setTimeout(triggerAutocomplete, 0); } }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeEditor(); }); if (currentPlatform.key === 'nowcoder') { GM_addStyle(` pre code.hljs { padding: 0 !important; } .uoj-code-highlight { padding: 10px 0 10px 10px !important; margin: 0 !important; } .uoj-code-highlight code { display: block; line-height: 1.5 !important; font-size: 14px !important; font-family: 'Consolas', 'Monaco', monospace !important; } .uoj-code-editor { padding: 12px 12px 12px 12px !important; margin: 0 !important; line-height: 1.5 !important; font-size: 14px !important; font-family: 'Consolas', 'Monaco', monospace !important; text-indent: 0 !important; border: none !important; } .uoj-line-numbers { padding: 12px 8px 12px 8px !important; line-height: 1.5 !important; font-size: 14px !important; } .uoj-line-numbers div { line-height: 1.5 !important; height: 21px !important; margin: 0 !important; padding: 0 !important; } `); } else if (currentPlatform.key === 'codeforces') { GM_addStyle(` .uoj-code-editor, .uoj-code-highlight, .uoj-line-numbers { font-family: 'Courier New', 'Courier', monospace !important; line-height: 1.6 !important; } .uoj-line-numbers div { height: 22.4px; } `); } else if (currentPlatform.key === 'vjudge') { GM_addStyle(` #uojEditorOverlay .uoj-code-highlight, #uojEditorOverlay .uoj-code-highlight code, #uojEditorOverlay .uoj-code-highlight pre, #uojEditorOverlay .uoj-code-highlight span { background: transparent !important; } #uojEditorOverlay .uoj-code-highlight .hljs-keyword, #uojEditorOverlay .uoj-code-highlight .hljs-type, #uojEditorOverlay .uoj-code-highlight .hljs-built_in { color: #ff7b72 !important; } #uojEditorOverlay .uoj-code-highlight .hljs-string, #uojEditorOverlay .uoj-code-highlight .hljs-regexp { color: #a5d6ff !important; } #uojEditorOverlay .uoj-code-highlight .hljs-comment, #uojEditorOverlay .uoj-code-highlight .hljs-formula { color: #8b949e !important; } #uojEditorOverlay .uoj-code-highlight .hljs-number, #uojEditorOverlay .uoj-code-highlight .hljs-literal { color: #79c0ff !important; } #uojEditorOverlay .uoj-code-highlight .hljs-title, #uojEditorOverlay .uoj-code-highlight .hljs-title.function_, #uojEditorOverlay .uoj-code-highlight .hljs-function { color: #d2a8ff !important; } #uojEditorOverlay .uoj-code-highlight .hljs-symbol { color: #ffa657 !important; } #uojEditorOverlay .uoj-code-highlight .hljs-variable-enhanced { color: #79c0ff !important; font-weight: 500 !important; } #uojEditorOverlay .uoj-code-highlight .hljs-operator-enhanced { color: #ff7b72 !important; font-weight: bold !important; } #uojEditorOverlay .uoj-code-highlight .hljs-type-enhanced { color: #ffa657 !important; font-weight: 600 !important; } #uojEditorOverlay .uoj-code-highlight .bracket-level-0 { color: #FFD700 !important; } #uojEditorOverlay .uoj-code-highlight .bracket-level-1 { color: #DA70D6 !important; } #uojEditorOverlay .uoj-code-highlight .bracket-level-2 { color: #87CEEB !important; } #uojEditorOverlay .uoj-code-highlight .bracket-level-3 { color: #98FB98 !important; } #uojEditorOverlay .uoj-code-highlight .bracket-level-4 { color: #FFA07A !important; } #uojEditorOverlay .uoj-code-highlight .bracket-level-5 { color: #F0E68C !important; } `); } else if (currentPlatform.key === 'luogu') { GM_addStyle(` .uoj-code-highlight, .uoj-code-highlight *, .uoj-code-highlight code, .uoj-code-highlight code * { color: #ffffff !important; } .uoj-code-highlight .hljs-keyword, .uoj-code-highlight .hljs-type, .uoj-code-highlight .hljs-built_in { color: #ff7b72 !important; } .uoj-code-highlight .hljs-string, .uoj-code-highlight .hljs-regexp { color: #a5d6ff !important; } .uoj-code-highlight .hljs-comment, .uoj-code-highlight .hljs-formula { color: #8b949e !important; } .uoj-code-highlight .hljs-number, .uoj-code-highlight .hljs-literal { color: #79c0ff !important; } .uoj-code-highlight .hljs-title, .uoj-code-highlight .hljs-function { color: #d2a8ff !important; } .uoj-code-highlight .hljs-variable-enhanced { color: #79c0ff !important; font-weight: 500 !important; } .uoj-code-highlight .hljs-operator-enhanced { color: #ff7b72 !important; font-weight: bold !important; } .uoj-code-highlight .hljs-type-enhanced { color: #ffa657 !important; font-weight: 600 !important; } .uoj-code-highlight .bracket-level-0 { color: #FFD700 !important; } .uoj-code-highlight .bracket-level-1 { color: #DA70D6 !important; } .uoj-code-highlight .bracket-level-2 { color: #87CEEB !important; } .uoj-code-highlight .bracket-level-3 { color: #98FB98 !important; } .uoj-code-highlight .bracket-level-4 { color: #FFA07A !important; } .uoj-code-highlight .bracket-level-5 { color: #F0E68C !important; } `); } } function openEditor() { problemId = currentPlatform.selectors.problemId(); console.log('[Universal OJ] 打开编辑器,题目ID:', problemId); createLightbox(); const overlay = document.getElementById('uojEditorOverlay'); overlay.classList.add('active'); document.body.style.overflow = 'hidden'; const problemContentEl = document.getElementById('uojProblemContent'); problemContentEl.innerHTML = '

⏳ 正在加载题目信息...

'; const problemInfo = currentPlatform.getProblemInfo(); if (problemInfo instanceof Promise) { problemInfo.then(html => { problemContentEl.innerHTML = html; setTimeout(() => { if (window.MathJax && window.MathJax.typeset) { window.MathJax.typeset([problemContentEl]); } }, 500); }); } else { problemContentEl.innerHTML = problemInfo; } const saved = localStorage.getItem(`uoj_code_${problemId}_${currentLang}`); const editor = document.getElementById('uojCodeEditor'); editor.value = saved || codeTemplates[currentLang]; updateLineNumbers(); updateHighlight(); updateCursorInfo(); setTimeout(() => editor.focus(), 100); } function closeEditor() { const overlay = document.getElementById('uojEditorOverlay'); if (overlay) { overlay.classList.remove('active'); document.body.style.overflow = ''; } } function handleConfirm() { const editor = document.getElementById('uojCodeEditor'); const success = currentPlatform.syncCode(editor.value); const btn = document.getElementById('uojConfirmBtn'); const originalText = btn.innerHTML; if (success) { btn.innerHTML = '✅ 已载入'; setTimeout(() => { btn.innerHTML = originalText; closeEditor(); }, 800); } else { btn.innerHTML = '❌ 失败'; setTimeout(() => { btn.innerHTML = originalText; }, 1500); alert('代码同步失败,请手动复制粘贴'); } } function changeLanguage() { const editor = document.getElementById('uojCodeEditor'); const select = document.getElementById('uojLangSelect'); localStorage.setItem(`uoj_code_${problemId}_${currentLang}`, editor.value); currentLang = select.value; const saved = localStorage.getItem(`uoj_code_${problemId}_${currentLang}`); editor.value = saved || codeTemplates[currentLang]; updateLineNumbers(); updateHighlight(); updateCursorInfo(); } function updateCode() { updateLineNumbers(); updateHighlight(); updateCursorInfo(); const editor = document.getElementById('uojCodeEditor'); if (editor) { localStorage.setItem(`uoj_code_${problemId}_${currentLang}`, editor.value); } } function updateHighlight() { const editor = document.getElementById('uojCodeEditor'); const highlightCode = document.getElementById('uojHighlightCode'); if (!editor || !highlightCode) return; let content = editor.value; if (content.endsWith('\n')) { highlightCode.textContent = content + ' '; } else { highlightCode.textContent = content + '\n '; } highlightCode.removeAttribute('data-highlighted'); highlightCode.className = `${langClasses[currentLang]} hljs`; try { if (typeof hljs === 'undefined') { console.error('[Universal OJ] highlight.js 未加载'); return; } console.log('[Universal OJ] 代码高亮:', currentLang); hljs.highlightElement(highlightCode); console.log('[Universal OJ] 高亮完成'); requestAnimationFrame(() => { const code = document.getElementById('uojHighlightCode'); if (code) { console.log('[Universal OJ] 高亮后的HTML:', code.innerHTML.substring(0, 200)); console.log('[Universal OJ] 应用增强样式'); applyAllEnhancements(code); console.log('[Universal OJ] 增强后的HTML:', code.innerHTML.substring(0, 200)); } }); } catch (e) { console.error('[Universal OJ] 失败:', e); } syncScroll(); } function applyAllEnhancements(element) { applyBracketColors(element); applyStdTypes(element); applyOperators(element); applyVariableHighlight(element); } function applyBracketColors(element) { const brackets = ['{', '}', '[', ']', '(', ')']; const colors = 6; let stack = []; function processNode(node) { if (node.nodeType === Node.TEXT_NODE) { const text = node.textContent; if (!/[(){}\[\]]/.test(text)) return; const fragment = document.createDocumentFragment(); let lastIdx = 0; for (let i = 0; i < text.length; i++) { const char = text[i]; if (brackets.includes(char)) { if (i > lastIdx) { fragment.appendChild(document.createTextNode(text.substring(lastIdx, i))); } const span = document.createElement('span'); let level = 0; if (['{', '[', '('].includes(char)) { level = stack.length % colors; stack.push({ char, level }); } else { const pair = { '}': '{', ']': '[', ')': '(' }; if (stack.length > 0 && stack[stack.length - 1].char === pair[char]) { level = stack.pop().level; } else { level = stack.length % colors; } } span.className = `bracket-level-${level}`; span.textContent = char; fragment.appendChild(span); lastIdx = i + 1; } } if (lastIdx < text.length) { fragment.appendChild(document.createTextNode(text.substring(lastIdx))); } if (lastIdx > 0) { node.parentNode.replaceChild(fragment, node); } } else if (node.nodeType === Node.ELEMENT_NODE) { if (node.className && ( node.className.includes('bracket-level') || node.className.includes('hljs-keyword') || node.className.includes('hljs-string') || node.className.includes('hljs-comment') || node.className.includes('hljs-number') || node.className.includes('hljs-title') || node.className.includes('hljs-type') || node.className.includes('hljs-built_in') )) return; const children = Array.from(node.childNodes); children.forEach(processNode); } } processNode(element); } function applyStdTypes(element) { const typeMap = { cpp: ['vector', 'string', 'map', 'set', 'unordered_map', 'unordered_set', 'list', 'deque', 'queue', 'stack', 'priority_queue', 'pair', 'cin', 'cout', 'cerr', 'endl', 'nullptr', 'NULL'], c: ['NULL', 'size_t', 'FILE'], java: ['String', 'Integer', 'ArrayList', 'HashMap', 'Scanner', 'System'], python: ['list', 'dict', 'set', 'tuple', 'str', 'True', 'False', 'None'], go: ['string', 'map', 'slice', 'nil', 'make', 'len', 'append'], javascript: ['console', 'Array', 'Object', 'String', 'Number'] }; const types = typeMap[currentLang] || []; if (types.length === 0) return; function processNode(node) { if (node.nodeType === Node.TEXT_NODE) { const text = node.textContent; const matches = []; types.forEach(type => { const regex = new RegExp(`\\b${type}\\b`, 'g'); let match; while ((match = regex.exec(text)) !== null) { matches.push({ start: match.index, end: match.index + type.length, text: type }); } }); if (matches.length === 0) return; matches.sort((a, b) => a.start - b.start); const filtered = []; let lastEnd = -1; matches.forEach(m => { if (m.start >= lastEnd) { filtered.push(m); lastEnd = m.end; } }); if (filtered.length === 0) return; const fragment = document.createDocumentFragment(); let pos = 0; filtered.forEach(m => { if (m.start > pos) { fragment.appendChild(document.createTextNode(text.substring(pos, m.start))); } const span = document.createElement('span'); span.className = 'hljs-type-enhanced'; span.textContent = m.text; fragment.appendChild(span); pos = m.end; }); if (pos < text.length) { fragment.appendChild(document.createTextNode(text.substring(pos))); } node.parentNode.replaceChild(fragment, node); } else if (node.nodeType === Node.ELEMENT_NODE) { if (node.className && ( node.className.includes('hljs-string') || node.className.includes('hljs-comment') || node.className.includes('hljs-type-enhanced') || node.className.includes('bracket-level') )) return; Array.from(node.childNodes).forEach(processNode); } } processNode(element); } function applyOperators(element) { const operators = [ '==', '!=', '<=', '>=', '&&', '||', '<<', '>>', '++', '--', '+=', '-=', '*=', '/=', '%=', '->', '::', '=', '+', '-', '*', '/', '%', '<', '>', '!', '&', '|', '^', '~' ]; operators.sort((a, b) => b.length - a.length); function processNode(node) { if (node.nodeType === Node.TEXT_NODE) { const text = node.textContent; if (!/[=!<>&|+\-*\/%~^]/.test(text)) return; const fragment = document.createDocumentFragment(); let pos = 0; while (pos < text.length) { let matched = false; for (const op of operators) { if (text.substr(pos, op.length) === op) { const span = document.createElement('span'); span.className = 'hljs-operator-enhanced'; span.textContent = op; fragment.appendChild(span); pos += op.length; matched = true; break; } } if (!matched) { const nextOpPos = text.slice(pos).search(/[=!<>&|+\-*\/%~^]/); const endPos = nextOpPos === -1 ? text.length : pos + nextOpPos; fragment.appendChild(document.createTextNode(text.substring(pos, endPos))); pos = endPos; } } if (fragment.childNodes.length > 1 || (fragment.childNodes.length === 1 && fragment.firstChild.nodeType === Node.ELEMENT_NODE)) { node.parentNode.replaceChild(fragment, node); } } else if (node.nodeType === Node.ELEMENT_NODE) { if (node.className && ( node.className.includes('hljs-string') || node.className.includes('hljs-comment') || node.className.includes('hljs-number') || node.className.includes('hljs-operator-enhanced') || node.className.includes('bracket-level') )) return; Array.from(node.childNodes).forEach(processNode); } } processNode(element); } function applyVariableHighlight(element) { const patterns = { cpp: /\b(?:int|long|float|double|char|bool|string|auto|void)\s+(\w+)/g, c: /\b(?:int|long|float|double|char|void)\s+(\w+)/g, python: /\b(\w+)\s*=/g, java: /\b(?:int|long|float|double|char|boolean|String)\s+(\w+)/g, javascript: /\b(?:var|let|const)\s+(\w+)/g, go: /(\w+)\s*:=/g }; const pattern = patterns[currentLang]; if (!pattern) return; const fullText = element.textContent; const varNames = new Set(); pattern.lastIndex = 0; let match; while ((match = pattern.exec(fullText)) !== null) { if (match[1] && !/^(true|false|null|NULL|nullptr)$/.test(match[1])) { varNames.add(match[1]); } } if (varNames.size === 0) return; function processNode(node) { if (node.nodeType === Node.TEXT_NODE) { const text = node.textContent; const matches = []; varNames.forEach(varName => { const regex = new RegExp(`\\b${varName}\\b`, 'g'); let m; while ((m = regex.exec(text)) !== null) { matches.push({ start: m.index, end: m.index + varName.length, text: varName }); } }); if (matches.length === 0) return; matches.sort((a, b) => a.start - b.start); const filtered = []; let lastEnd = -1; matches.forEach(m => { if (m.start >= lastEnd) { filtered.push(m); lastEnd = m.end; } }); if (filtered.length === 0) return; const fragment = document.createDocumentFragment(); let pos = 0; filtered.forEach(m => { if (m.start > pos) { fragment.appendChild(document.createTextNode(text.substring(pos, m.start))); } const span = document.createElement('span'); span.className = 'hljs-variable-enhanced'; span.textContent = m.text; fragment.appendChild(span); pos = m.end; }); if (pos < text.length) { fragment.appendChild(document.createTextNode(text.substring(pos))); } node.parentNode.replaceChild(fragment, node); } else if (node.nodeType === Node.ELEMENT_NODE) { if (node.className && ( node.className.includes('hljs-keyword') || node.className.includes('hljs-string') || node.className.includes('hljs-comment') || node.className.includes('hljs-variable-enhanced') || node.className.includes('hljs-type-enhanced') || node.className.includes('bracket-level') )) return; Array.from(node.childNodes).forEach(processNode); } } processNode(element); } function updateLineNumbers() { const editor = document.getElementById('uojCodeEditor'); const lineNumbers = document.getElementById('uojLineNumbers'); if (!editor || !lineNumbers) return; const lines = editor.value.split('\n').length; const lineHtml = Array(lines).fill(0).map((_, i) => `
${i + 1}
` ).join(''); lineNumbers.innerHTML = lineHtml; } function syncScroll() { const editor = document.getElementById('uojCodeEditor'); const highlightPre = document.querySelector('.uoj-code-highlight'); const lineNumbers = document.getElementById('uojLineNumbers'); if (editor && highlightPre && lineNumbers) { highlightPre.scrollTop = editor.scrollTop; highlightPre.scrollLeft = editor.scrollLeft; lineNumbers.scrollTop = editor.scrollTop; } } function updateCursorInfo() { const editor = document.getElementById('uojCodeEditor'); const info = document.getElementById('uojEditorInfo'); if (!editor || !info) return; const value = editor.value; const pos = editor.selectionStart; const lines = value.substring(0, pos).split('\n'); const line = lines.length; const col = lines[lines.length - 1].length + 1; info.textContent = `行 ${line}, 列 ${col} | ${langNames[currentLang]}`; } let autocompleteState = { active: false, items: [], selectedIndex: 0, startPos: 0, endPos: 0, word: '' }; function getWordAtCursor(text, pos) { const before = text.substring(0, pos); const match = before.match(/[a-zA-Z_][a-zA-Z0-9_]*$/); return match ? match[0] : ''; } function getAutocompleteItems(word, lang) { if (!word || word.length < 2) return []; const data = autoCompleteData[lang]; if (!data) return []; const items = []; const lowerWord = word.toLowerCase(); data.keywords.forEach(keyword => { if (keyword.toLowerCase().startsWith(lowerWord)) { items.push({ label: keyword, type: 'keyword', insertText: keyword }); } }); data.types.forEach(type => { if (type.toLowerCase().startsWith(lowerWord)) { items.push({ label: type, type: 'type', insertText: type }); } }); Object.entries(data.snippets).forEach(([key, value]) => { if (key.toLowerCase().startsWith(lowerWord)) { items.push({ label: key, type: 'snippet', insertText: value, desc: value.substring(0, 30) + (value.length > 30 ? '...' : '') }); } }); items.sort((a, b) => { const aExact = a.label.toLowerCase() === lowerWord; const bExact = b.label.toLowerCase() === lowerWord; if (aExact && !bExact) return -1; if (!aExact && bExact) return 1; return a.label.length - b.label.length; }); return items.slice(0, 10); } function showAutocomplete(items, x, y) { const container = document.getElementById('uojAutocomplete'); if (!container || items.length === 0) { hideAutocomplete(); return; } autocompleteState.items = items; autocompleteState.selectedIndex = 0; autocompleteState.active = true; container.innerHTML = items.map((item, index) => `
${item.label} ${item.desc ? `${item.desc}` : ''}
`).join(''); container.style.display = 'block'; container.style.left = x + 'px'; container.style.top = y + 'px'; container.querySelectorAll('.uoj-autocomplete-item').forEach(el => { el.addEventListener('click', () => { selectAutocompleteItem(parseInt(el.dataset.index)); }); }); } function hideAutocomplete() { const container = document.getElementById('uojAutocomplete'); if (container) { container.style.display = 'none'; } autocompleteState.active = false; autocompleteState.items = []; autocompleteState.selectedIndex = 0; } function updateAutocompleteSelection(newIndex) { const container = document.getElementById('uojAutocomplete'); if (!container) return; const items = container.querySelectorAll('.uoj-autocomplete-item'); items.forEach((item, index) => { item.classList.toggle('selected', index === newIndex); }); autocompleteState.selectedIndex = newIndex; const selectedItem = items[newIndex]; if (selectedItem) { selectedItem.scrollIntoView({ block: 'nearest' }); } } function selectAutocompleteItem(index) { const editor = document.getElementById('uojCodeEditor'); if (!editor || !autocompleteState.active) return; const item = autocompleteState.items[index]; if (!item) return; const value = editor.value; const before = value.substring(0, autocompleteState.startPos); const after = value.substring(autocompleteState.endPos); editor.value = before + item.insertText + after; const newPos = autocompleteState.startPos + item.insertText.length; editor.selectionStart = editor.selectionEnd = newPos; updateCode(); hideAutocomplete(); editor.focus(); } function triggerAutocomplete() { const editor = document.getElementById('uojCodeEditor'); if (!editor) return; const pos = editor.selectionStart; const value = editor.value; const word = getWordAtCursor(value, pos); if (!word || word.length < 1) { hideAutocomplete(); return; } autocompleteState.word = word; autocompleteState.startPos = pos - word.length; autocompleteState.endPos = pos; const items = getAutocompleteItems(word, currentLang); if (items.length === 0) { hideAutocomplete(); return; } const lines = value.substring(0, pos).split('\n'); const currentLine = lines[lines.length - 1]; const lineHeight = 21; const charWidth = 8; const x = currentLine.length * charWidth + 60; const y = (lines.length - 1) * lineHeight + 12 + lineHeight; showAutocomplete(items, x, y); } function handleKey(e) { const editor = document.getElementById('uojCodeEditor'); if (!editor) return; if (autocompleteState.active) { if (e.key === 'ArrowDown') { e.preventDefault(); const newIndex = (autocompleteState.selectedIndex + 1) % autocompleteState.items.length; updateAutocompleteSelection(newIndex); return; } if (e.key === 'ArrowUp') { e.preventDefault(); const newIndex = (autocompleteState.selectedIndex - 1 + autocompleteState.items.length) % autocompleteState.items.length; updateAutocompleteSelection(newIndex); return; } if (e.key === 'Enter' || e.key === 'Tab') { e.preventDefault(); selectAutocompleteItem(autocompleteState.selectedIndex); return; } if (e.key === 'Escape') { e.preventDefault(); hideAutocomplete(); return; } } const start = editor.selectionStart; const end = editor.selectionEnd; const value = editor.value; const before = value.substring(0, start); const after = value.substring(end); const pairs = { '(': ')', '[': ']', '{': '}', '"': '"', "'": "'", '<': '>' }; const closingChars = [')', ']', '}', '"', "'", '>']; if (closingChars.includes(e.key)) { const nextChar = value.charAt(start); if (nextChar === e.key) { e.preventDefault(); editor.selectionStart = editor.selectionEnd = start + 1; hideAutocomplete(); return; } } if (pairs[e.key]) { e.preventDefault(); const pair = pairs[e.key]; if (start !== end) { const selectedText = value.substring(start, end); editor.value = before + e.key + selectedText + pair + after; editor.selectionStart = start + 1; editor.selectionEnd = start + 1 + selectedText.length; } else { editor.value = before + e.key + pair + after; editor.selectionStart = editor.selectionEnd = start + 1; } updateCode(); return; } if (e.key === 'Enter') { e.preventDefault(); const lines = before.split('\n'); const currentLine = lines[lines.length - 1]; const indentMatch = currentLine.match(/^\s*/); const indent = indentMatch ? indentMatch[0] : ""; let extraIndent = ""; let closingBrace = ""; const charBefore = value.charAt(start - 1); const charAfter = value.charAt(start); const isInBrackets = (charBefore === '{' && charAfter === '}') || (charBefore === '[' && charAfter === ']') || (charBefore === '(' && charAfter === ')'); if (isInBrackets) { extraIndent = " "; closingBrace = "\n" + indent; } else if (currentLine.trim().endsWith('{')) { extraIndent = " "; } const insertText = "\n" + indent + extraIndent; editor.value = before + insertText + closingBrace + after; editor.selectionStart = editor.selectionEnd = start + insertText.length; updateCode(); return; } if (e.key === 'Backspace' && start === end) { const charBefore = value.charAt(start - 1); const charAfter = value.charAt(start); if (pairs[charBefore] === charAfter) { e.preventDefault(); editor.value = value.substring(0, start - 1) + value.substring(start + 1); editor.selectionStart = editor.selectionEnd = start - 1; updateCode(); return; } } if (e.key === 'Tab') { e.preventDefault(); if (start !== end) { const selectedText = value.substring(start, end); const lines = selectedText.split('\n'); if (e.shiftKey) { const unindented = lines.map(line => { if (line.startsWith(' ')) return line.substring(4); if (line.startsWith('\t')) return line.substring(1); return line; }).join('\n'); editor.value = before + unindented + after; editor.selectionStart = start; editor.selectionEnd = start + unindented.length; } else { const indented = lines.map(line => ' ' + line).join('\n'); editor.value = before + indented + after; editor.selectionStart = start; editor.selectionEnd = start + indented.length; } } else { editor.value = before + " " + after; editor.selectionStart = editor.selectionEnd = start + 4; } updateCode(); return; } if (e.key === '/' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); const lines = value.split('\n'); const startLine = value.substring(0, start).split('\n').length - 1; const endLine = value.substring(0, end).split('\n').length - 1; const commentSymbol = currentLang === 'python' ? '#' : '//'; let allCommented = true; for (let i = startLine; i <= endLine; i++) { if (!lines[i].trim().startsWith(commentSymbol)) { allCommented = false; break; } } for (let i = startLine; i <= endLine; i++) { if (allCommented) { lines[i] = lines[i].replace(new RegExp(`^(\\s*)${commentSymbol}\\s?`), '$1'); } else { const indent = lines[i].match(/^\s*/)[0]; lines[i] = indent + commentSymbol + ' ' + lines[i].substring(indent.length); } } editor.value = lines.join('\n'); updateCode(); return; } setTimeout(updateCursorInfo, 0); } function addOpenButton() { if (document.getElementById('uojOpenBtn')) { console.log('[Universal OJ] 按钮已存在'); return true; } let container = null; let submitBtn = null; const buttons = document.querySelectorAll('button'); for (const btn of buttons) { const text = btn.textContent.toLowerCase(); if (text.includes('提交') || text.includes('submit')) { submitBtn = btn; container = btn.parentNode; console.log('[Universal OJ] 找到提交按钮:', btn); break; } } if (!container && currentPlatform.selectors.buttonContainer) { const selectors = currentPlatform.selectors.buttonContainer.split(','); for (const selector of selectors) { container = document.querySelector(selector.trim()); if (container) { console.log('[Universal OJ] 使用平台选择器找到容器:', selector); break; } } } if (!container) { switch(currentPlatform.key) { case 'jxau': container = document.querySelector('.ivu-row-flex .ivu-col-span-12:last-child') || document.querySelector('#submit-code .ivu-card-body'); break; case 'nowcoder': container = document.querySelector('.question-btns') || document.querySelector('.terminal-topic-operation') || document.querySelector('.question-operate'); break; case 'luogu': container = document.querySelector('.operation') || document.querySelector('.main .actions'); break; case 'codeforces': container = document.querySelector('.roundbox') || document.querySelector('.problem-statement'); break; } } if (!container) { console.warn('[Universal OJ] 未找到合适的按钮容器'); return false; } const btn = document.createElement('button'); btn.id = 'uojOpenBtn'; btn.type = 'button'; btn.className = 'uoj-open-btn'; btn.innerHTML = '✏️ 高级编辑器'; btn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); openEditor(); }); if (submitBtn) { submitBtn.parentNode.insertBefore(btn, submitBtn.nextSibling); console.log('[Universal OJ] 按钮已插入到提交按钮后面'); } else { container.appendChild(btn); console.log('[Universal OJ] 按钮已追加到容器'); } return true; } function init() { console.log('[Universal OJ] 开始初始化...'); console.log('[Universal OJ] 当前平台:', currentPlatform.name); console.log('[Universal OJ] URL:', window.location.href); const tryAddButton = () => { if (addOpenButton()) { console.log('[Universal OJ] ✅ 初始化成功'); return true; } return false; }; setTimeout(() => { if (tryAddButton()) return; let attempts = 0; const maxAttempts = 3; const interval = setInterval(() => { attempts++; console.log(`[Universal OJ] 尝试添加按钮 (${attempts}/${maxAttempts})`); if (tryAddButton() || attempts >= maxAttempts) { clearInterval(interval); if (attempts >= maxAttempts) { console.error('[Universal OJ] ❌ 无法添加按钮,请检查页面结构'); } } }, 1000); }, 2000); const observer = new MutationObserver((mutations) => { if (!document.getElementById('uojOpenBtn')) { tryAddButton(); } }); observer.observe(document.body, { childList: true, subtree: true }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();