<?php function uojHandleAtSign($str, $uri) { $referrers = array(); $res = preg_replace_callback('/@(@|[a-zA-Z0-9_]{1,20})/', function($matches) use (&$referrers) { if ($matches[1] === '@') { return '@'; } else { $user = queryUser($matches[1]); if ($user == null) { return $matches[0]; } else { $referrers[$user['username']] = ''; return '<span class="uoj-username">@'.$user['username'].'</span>'; } } }, $str); $referrers_list = array(); foreach ($referrers as $referrer => $val) { $referrers_list[] = $referrer; } return array($res, $referrers_list); } function uojFilePreview($file_name, $output_limit, $file_type = 'text') { switch ($file_type) { case 'text': return strOmit(file_get_contents($file_name, false, null, 0, $output_limit + 4), $output_limit); default: return strOmit(shell_exec('xxd -g 4 -l 5000 ' . escapeshellarg($file_name) . ' | head -c ' . ($output_limit + 4)), $output_limit); } } function uojIncludeView($name, $view_params = array()) { global $REQUIRE_LIB; extract($view_params); include $_SERVER['DOCUMENT_ROOT'].'/app/views/'.$name.'.php'; } function redirectTo($url) { header('Location: '.$url); die(); } function permanentlyRedirectTo($url) { header("HTTP/1.1 301 Moved Permanently"); header('Location: '.$url); die(); } function redirectToLogin() { if (UOJContext::isAjax()) { die('please <a href="'.HTML::url('/login').'">login</a>'); } else { header('Location: '.HTML::url('/login')); die(); } } function becomeMsgPage($msg, $title = '消息') { global $REQUIRE_LIB; if (UOJContext::isAjax()) { die($msg); } else { if (!isset($_COOKIE['bootstrap4'])) { $REQUIRE_LIB['bootstrap5'] = ''; } echoUOJPageHeader($title); echo $msg; echoUOJPageFooter(); die(); } } function become404Page($message = '未找到页面。') { header($_SERVER['SERVER_PROTOCOL'] . " 404 Not Found", true, 404); becomeMsgPage('<div class="text-center"><div style="font-size:150px">404</div><p>' . $message . '</p></div>', '404'); } function become403Page($message = '访问被拒绝,您可能需要适当的权限以访问此页面。') { header($_SERVER['SERVER_PROTOCOL'] . " 403 Forbidden", true, 403); becomeMsgPage('<div class="text-center"><div style="font-size:150px">403</div><p>' . $message . '</p></div>', '403'); } function getUserLink($username) { if (validateUsername($username) && ($user = queryUser($username)) && $user['usergroup'] != 'B') { $realname = $user['realname']; if ($realname == "") { return '<span class="uoj-username">'.$username.'</span>'; } else { return '<span class="uoj-username" data-realname="'.$realname.'">'.$username.'</span>'; } } else { $esc_username = HTML::escape($username); return '<span>'.$esc_username.'</span>'; } } function getUserName($username, $realname = null) { if ($realname == null) { if (validateUsername($username) && ($user = queryUser($username))) { $realname = $user['realname']; } } if ($realname == "") { return "$username"; } else { return "$username ($realname)"; } } function getProblemLink($problem, $problem_title = '!title_only') { global $REQUIRE_LIB; if ($problem_title == '!title_only') { $problem_title = $problem['title']; } elseif ($problem_title == '!id_and_title') { $problem_title = "#${problem['id']}. ${problem['title']}"; } $result = '<a '; if (isset($REQUIRE_LIB['bootstrap5'])) { $result .= ' class="text-decoration-none" '; } $result .= ' href="/problem/'.$problem['id'].'">'.$problem_title.'</a>'; return $result; } function getContestProblemLink($problem, $contest_id, $problem_title = '!title_only') { global $REQUIRE_LIB; if ($problem_title == '!title_only') { $problem_title = $problem['title']; } elseif ($problem_title == '!id_and_title') { $problem_title = "#{$problem['id']}. {$problem['title']}"; } $result = '<a '; if (isset($REQUIRE_LIB['bootstrap5'])) { $result .= ' class="text-decoration-none" '; } $result .= ' href="/contest/'.$contest_id.'/problem/'.$problem['id'].'">'.$problem_title.'</a>'; return $result; } function getBlogLink($id) { global $REQUIRE_LIB; $result = ''; if (validateUInt($id) && $blog = queryBlog($id)) { $result = '<a '; if (isset($REQUIRE_LIB['bootstrap5'])) { $result .= ' class="text-decoration-none" '; } $result .= ' href="/blogs/'.$id.'">'.$blog['title'].'</a>'; } return $result; } function getClickZanBlock($type, $id, $cnt, $val = null, $show_text = true) { if ($val == null) { $val = queryZanVal($id, $type, Auth::user()); } return '<div class="uoj-click-zan-block" data-id="'.$id.'" data-type="'.$type.'" data-val="'.$val.'" data-cnt="'.$cnt.'" '.($show_text ? ' data-show-text="1" ' : '') . '></div>'; } function getLongTablePageRawUri($page) { $path = strtok(UOJContext::requestURI(), '?'); $query_string = strtok('?'); parse_str($query_string, $param); $param['page'] = $page; if ($page == 1) { unset($param['page']); } if ($param) { return $path . '?' . http_build_query($param); } else { return $path; } } function getLongTablePageUri($page) { return HTML::escape(getLongTablePageRawUri($page)); } function echoLongTable($col_names, $table_name, $cond, $tail, $header_row, $print_row, $config) { global $REQUIRE_LIB; $pag_config = $config; $pag_config['col_names'] = $col_names; $pag_config['table_name'] = $table_name; $pag_config['cond'] = $cond; $pag_config['tail'] = $tail; $pag = new Paginator($pag_config); $div_classes = isset($config['div_classes']) ? $config['div_classes'] : array('table-responsive'); $table_classes = isset($config['table_classes']) ? $config['table_classes'] : (isset($REQUIRE_LIB['bootstrap5']) ? array('table', 'table-bordered', 'table-striped', 'text-center') : array('table', 'table-bordered', 'table-hover', 'table-striped', 'table-text-center')); if (isset($config['head_pagination']) && $config['head_pagination']) { echo $pag->pagination(); } echo '<div class="', join($div_classes, ' '), '">'; echo '<table class="', join($table_classes, ' '), '">'; echo '<thead>'; echo $header_row; echo '</thead>'; echo '<tbody>'; foreach ($pag->get() as $idx => $row) { if (isset($config['get_row_index'])) { $print_row($row, $idx); } else { $print_row($row); } } if ($pag->isEmpty()) { echo '<tr><td colspan="233">'.UOJLocale::get('none').'</td></tr>'; } echo '</tbody>'; echo '</table>'; echo '</div>'; if (isset($config['print_after_table'])) { $fun = $config['print_after_table']; $fun(); } echo $pag->pagination(); } function getSubmissionStatusDetails($submission) { $html = '<td colspan="233" style="vertical-align: middle">'; $out_status = explode(', ', $submission['status'])[0]; $fly = '<img src="/images/utility/qpx_n/b37.gif" alt="小熊像超人一样飞" class="img-rounded" />'; $think = '<img src="/images/utility/qpx_n/b29.gif" alt="小熊像在思考" class="img-rounded" />'; if ($out_status == 'Judged') { $status_text = '<strong>Judged!</strong>'; $status_img = $fly; } else { if ($submission['status_details'] !== '') { $status_img = $fly; $status_text = HTML::escape($submission['status_details']); } else { $status_img = $think; $status_text = $out_status; } } $html .= '<div class="uoj-status-details-img-div">' . $status_img . '</div>'; $html .= '<div class="uoj-status-details-text-div">' . $status_text . '</div>'; $html .= '</td>'; return $html; } function echoSubmission($submission, $config, $user) { global $REQUIRE_LIB; $problem = queryProblemBrief($submission['problem_id']); $submitterLink = getUserLink($submission['submitter']); if ($submission['score'] == null) { $used_time_str = "/"; $used_memory_str = "/"; } else { $used_time_str = $submission['used_time'] . 'ms'; $used_memory_str = $submission['used_memory'] . 'kb'; } $status = explode(', ', $submission['status'])[0]; $show_status_details = Auth::check() && $submission['submitter'] === Auth::id() && $status !== 'Judged'; if (!$show_status_details) { echo '<tr>'; } else { echo '<tr class="warning">'; } if (!isset($config['id_hidden'])) { echo '<td><a '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' class="text-decoration-none" '; } echo ' href="/submission/', $submission['id'], '">#', $submission['id'], '</a></td>'; } if (!isset($config['problem_hidden'])) { if ($submission['contest_id']) { echo '<td>', getContestProblemLink($problem, $submission['contest_id'], '!id_and_title'), '</td>'; } else { echo '<td>', getProblemLink($problem, '!id_and_title'), '</td>'; } } if (!isset($config['submitter_hidden'])) { echo '<td>', $submitterLink, '</td>'; } if (!isset($config['result_hidden'])) { echo '<td>'; if ($status == 'Judged') { if ($submission['score'] == null) { echo '<a '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' class="text-decoration-none small" '; } else { echo ' class="small" '; } echo ' href="/submission/', $submission['id'], '">', $submission['result_error'], '</a>'; } else { echo '<a href="/submission/', $submission['id'], '" class="uoj-score">', $submission['score'], '</a>'; } } else { echo '<a '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' class="text-decoration-none small" '; } else { echo ' class="small" '; } echo ' href="/submission/', $submission['id'], '">', $status, '</a>'; } echo '</td>'; } if (!isset($config['used_time_hidden'])) { echo '<td>', $used_time_str, '</td>'; } if (!isset($config['used_memory_hidden'])) { echo '<td>', $used_memory_str, '</td>'; } echo '<td>', '<a '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' class="text-decoration-none" '; } echo ' href="/submission/', $submission['id'], '">', $submission['language'], '</a>', '</td>'; if ($submission['tot_size'] < 1024) { $size_str = $submission['tot_size'] . 'b'; } else { $size_str = sprintf("%.1f", $submission['tot_size'] / 1024) . 'kb'; } echo '<td>', $size_str, '</td>'; if (!isset($config['submit_time_hidden'])) { echo '<td><small>', $submission['submit_time'], '</small></td>'; } if (!isset($config['judge_time_hidden'])) { echo '<td><small>', $submission['judge_time'], '</small></td>'; } echo '</tr>'; if ($show_status_details) { echo '<tr id="', "status_details_{$submission['id']}", '" class="info">'; echo getSubmissionStatusDetails($submission); echo '</tr>'; echo '<script type="text/javascript">update_judgement_status_details('.$submission['id'].')</script>'; } } function echoSubmissionsListOnlyOne($submission, $config, $user) { global $REQUIRE_LIB; if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<div class="card mb-3 table-responsive">'; echo '<table class="table text-center uoj-table mb-0">'; } else { echo '<div class="table-responsive">'; echo '<table class="table table-bordered table-text-center">'; } echo '<thead>'; echo '<tr>'; if (!isset($config['id_hidden'])) { echo '<th>ID</th>'; } if (!isset($config['problem_hidden'])) { echo '<th>'.UOJLocale::get('problems::problem').'</th>'; } if (!isset($config['submitter_hidden'])) { echo '<th>'.UOJLocale::get('problems::submitter').'</th>'; } if (!isset($config['result_hidden'])) { echo '<th>'.UOJLocale::get('problems::result').'</th>'; } if (!isset($config['used_time_hidden'])) { echo '<th>'.UOJLocale::get('problems::used time').'</th>'; } if (!isset($config['used_memory_hidden'])) { echo '<th>'.UOJLocale::get('problems::used memory').'</th>'; } echo '<th>'.UOJLocale::get('problems::language').'</th>'; echo '<th>'.UOJLocale::get('problems::file size').'</th>'; if (!isset($config['submit_time_hidden'])) { echo '<th>'.UOJLocale::get('problems::submit time').'</th>'; } if (!isset($config['judge_time_hidden'])) { echo '<th>'.UOJLocale::get('problems::judge time').'</th>'; } echo '</tr>'; echo '</thead>'; echo '<tbody>'; echoSubmission($submission, $config, $user); echo '</tbody>'; echo '</table>'; echo '</div>'; } function echoSubmissionsList($cond, $tail, $config, $user) { global $REQUIRE_LIB; $header_row = '<tr>'; $col_names = array(); $col_names[] = 'submissions.status_details'; $col_names[] = 'submissions.status'; $col_names[] = 'submissions.result_error'; $col_names[] = 'submissions.score'; if (!isset($config['id_hidden'])) { $header_row .= '<th>ID</th>'; $col_names[] = 'submissions.id'; } if (!isset($config['problem_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::problem').'</th>'; $col_names[] = 'submissions.problem_id'; $col_names[] = 'submissions.contest_id'; } if (!isset($config['submitter_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::submitter').'</th>'; $col_names[] = 'submissions.submitter'; } if (!isset($config['result_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::result').'</th>'; } if (!isset($config['used_time_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::used time').'</th>'; $col_names[] = 'submissions.used_time'; } if (!isset($config['used_memory_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::used memory').'</th>'; $col_names[] = 'submissions.used_memory'; } $header_row .= '<th>'.UOJLocale::get('problems::language').'</th>'; $col_names[] = 'submissions.language'; $header_row .= '<th>'.UOJLocale::get('problems::file size').'</th>'; $col_names[] = 'submissions.tot_size'; if (!isset($config['submit_time_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::submit time').'</th>'; $col_names[] = 'submissions.submit_time'; } if (!isset($config['judge_time_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::judge time').'</th>'; $col_names[] = 'submissions.judge_time'; } $header_row .= '</tr>'; $table_name = isset($config['table_name']) ? $config['table_name'] : 'submissions'; if (!isProblemManager($user)) { if ($user != null) { $permission_cond = "submissions.is_hidden = false or submissions.submitter = '{$user['username']}' or (submissions.is_hidden = true and (submissions.problem_id in (select problem_id from problems_permissions where username = '{$user['username']}') or submissions.problem_id in (select id from problems where uploader = '{$user['username']}')))"; } else { $permission_cond = "submissions.is_hidden = false"; } if ($cond !== '1') { $cond = "($cond) and ($permission_cond)"; } else { $cond = $permission_cond; } } $table_config = isset($config['table_config']) ? $config['table_config'] : null; echoLongTable($col_names, $table_name, $cond, $tail, $header_row, function($submission) use ($config, $user) { echoSubmission($submission, $config, $user); }, $table_config); } function echoSubmissionContent($submission, $requirement) { global $REQUIRE_LIB; $zip_file = new ZipArchive(); $submission_content = json_decode($submission['content'], true); $zip_file->open(UOJContext::storagePath().$submission_content['file_name']); $config = array(); foreach ($submission_content['config'] as $config_key => $config_val) { $config[$config_val[0]] = $config_val[1]; } foreach ($requirement as $req) { if ($req['type'] == "source code") { $file_content = $zip_file->getFromName("{$req['name']}.code"); $file_content = uojTextEncode($file_content, array('allow_CR' => true, 'html_escape' => true)); $file_language = htmlspecialchars($config["{$req['name']}_language"]); $footer_text = UOJLocale::get('problems::source code').', '.UOJLocale::get('problems::language').': '.$file_language; switch ($file_language) { case 'C++': case 'C++11': case 'C++17': case 'C++20': case 'C++98': case 'C++03': $sh_class = 'sh_cpp language-cpp'; break; case 'Python2': case 'Python2.7': case 'Python3': $sh_class = 'sh_python language-python'; break; case 'Java8': case 'Java11': case 'Java17': $sh_class = 'sh_java language-java'; break; case 'C': $sh_class = 'sh_c language-c'; break; case 'Pascal': $sh_class = 'sh_pascal language-pascal'; break; default: $sh_class = ''; break; } echo '<div class="card border-info mb-3">'; echo '<div class="card-header bg-info">'; echo '<h4 class="card-title">'.$req['name'].'</h4>'; echo '</div>'; echo '<div class="card-body">'; echo '<pre><code class="'.$sh_class; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' bg-light rounded p-3 '; } echo '">'.$file_content."\n".'</code></pre>'; echo '</div>'; echo '<div class="card-footer">'.$footer_text.'</div>'; echo '</div>'; } elseif ($req['type'] == "text") { $file_content = $zip_file->getFromName("{$req['file_name']}", 504); $file_content = strOmit($file_content, 500); $file_content = uojTextEncode($file_content, array('allow_CR' => true, 'html_escape' => true)); $footer_text = UOJLocale::get('problems::text file'); echo '<div class="card border-info mb-3">'; echo '<div class="card-header bg-info">'; echo '<h4 class="card-title">'.$req['file_name'].'</h4>'; echo '</div>'; echo '<div class="card-body">'; echo '<pre class=" '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' bg-light rounded p-3 '; } echo " \">\n".$file_content."\n".'</pre>'; echo '</div>'; echo '<div class="card-footer">'.$footer_text.'</div>'; echo '</div>'; } } $zip_file->close(); } class JudgementDetailsPrinter { private $name; private $styler; private $dom; private $subtask_num; private function _print_c($node) { foreach ($node->childNodes as $child) { if ($child->nodeName == '#text') { echo htmlspecialchars($child->nodeValue); } else { $this->_print($child); } } } private function _print($node) { global $REQUIRE_LIB; if ($node->nodeName == 'error') { echo '<pre class=" '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' bg-light rounded p-3 '; } echo " \">\n"; $this->_print_c($node); echo "\n</pre>"; } elseif ($node->nodeName == 'tests') { echo '<div id="', $this->name, '_details_accordion">'; if (isset($REQUIRE_LIB['bootstrap5'])) { $this->_print_c($node); } if ($this->styler->show_small_tip) { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<div class="my-2 px-2 text-end text-muted">'; } else { echo '<div class="text-right text-muted">'; } echo '小提示:点击横条可展开更详细的信息', '</div>'; } elseif ($this->styler->ioi_contest_is_running) { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<div class="my-2 px-2 text-end text-muted">'; } else { echo '<div class="text-right text-muted">'; } echo 'IOI赛制比赛中不支持显示详细信息', '</div>'; } if (!isset($REQUIRE_LIB['bootstrap5'])) { $this->_print_c($node); } echo '</div>'; } elseif ($node->nodeName == 'subtask') { $subtask_num = $node->getAttribute('num'); $subtask_score = $node->getAttribute('score'); $subtask_info = $node->getAttribute('info'); echo '<div class="card ', $this->styler->getTestInfoClass($subtask_info); if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' border-0 rounded-0 border-bottom '; } else { echo ' mb-3 '; } echo '">'; $accordion_parent = "{$this->name}_details_accordion"; $accordion_collapse = "{$accordion_parent}_collapse_subtask_{$subtask_num}"; $accordion_collapse_accordion = "{$accordion_collapse}_accordion"; echo '<div class="card-header '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' uoj-submission-result-item bg-transparent rounded-0 border-0 '; } echo '" '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' data-bs-toggle="collapse" data-bs-parent="#', $accordion_parent, '" data-bs-target="#', $accordion_collapse, '" '; } else { echo ' data-toggle="collapse" data-parent="#', $accordion_parent, '" data-target="#', $accordion_collapse, '" '; } echo ' >'; echo '<div class="row">'; echo '<div class="col-sm-4">'; if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<h3 class="fs-5">'; } else { echo '<h3 class="card-title">'; } echo 'Subtask #', $subtask_num, ': ', '</h3>'; echo '</div>'; if ($this->styler->show_score) { echo '<div class="col-sm-2">'; if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<i class="bi bi-clipboard-check"></i> '; } else { echo 'score: '; } echo $subtask_score; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' pts'; } echo '</div>'; echo '<div class="col-sm-2 uoj-status-text">'; if (isset($REQUIRE_LIB['bootstrap5'])) { echo $this->styler->getTestInfoIcon($subtask_info); } echo htmlspecialchars($subtask_info); echo '</div>'; } else { echo '<div class="col-sm-4">'; if (isset($REQUIRE_LIB['bootstrap5'])) { echo $this->styler->getTestInfoIcon($subtask_info); } echo htmlspecialchars($subtask_info); echo '</div>'; } echo '</div>'; echo '</div>'; echo '<div id="', $accordion_collapse, '" class="card-collapse collapse">'; echo '<div class="card-body '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' pt-0 '; } echo '">'; echo '<div id="', $accordion_collapse_accordion, '" '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' class="border rounded overflow-hidden" '; } echo ' >'; $this->subtask_num = $subtask_num; $this->_print_c($node); $this->subtask_num = null; echo '</div>'; echo '</div>'; echo '</div>'; echo '</div>'; } elseif ($node->nodeName == 'test') { $test_info = $node->getAttribute('info'); $test_num = $node->getAttribute('num'); $test_score = $node->getAttribute('score'); $test_time = $node->getAttribute('time'); $test_memory = $node->getAttribute('memory'); echo '<div class="card ', $this->styler->getTestInfoClass($test_info); if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' border-0 rounded-0 border-bottom '; } else { echo ' mb-3 '; } echo '">'; $accordion_parent = "{$this->name}_details_accordion"; if ($this->subtask_num != null) { $accordion_parent .= "_collapse_subtask_{$this->subtask_num}_accordion"; } $accordion_collapse = "{$accordion_parent}_collapse_test_{$test_num}"; echo '<div class="card-header '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' uoj-submission-result-item bg-transparent rounded-0 border-0 '; } echo '" '; if (!$this->styler->shouldFadeDetails($test_info)) { if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' data-bs-toggle="collapse" data-bs-parent="#', $accordion_parent, '" data-bs-target="#', $accordion_collapse, '" '; } else { echo ' data-toggle="collapse" data-parent="#', $accordion_parent, '" data-target="#', $accordion_collapse, '" '; } } echo '>'; echo '<div class="row">'; echo '<div class="col-sm-4">'; if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<h4 class="fs-5">'; } else { echo '<h4 class="card-title">'; } if ($test_num > 0) { echo 'Test #', $test_num, ': '; } else { echo 'Extra Test:'; } echo '</h4>'; echo '</div>'; if ($this->styler->show_score) { echo '<div class="col-sm-2">'; if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<i class="bi bi-clipboard-check"></i> '; } else { echo 'score: '; } echo $test_score; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' pts'; } echo '</div>'; if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<div class="col-sm-2 uoj-status-text">'; echo $this->styler->getTestInfoIcon($test_info); } else { echo '<div class="col-sm-2">'; } echo htmlspecialchars($test_info); echo '</div>'; } else { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<div class="col-sm-4 uoj-status-text">'; echo $this->styler->getTestInfoIcon($test_info); } else { echo '<div class="col-sm-4">'; } echo htmlspecialchars($test_info); echo '</div>'; } echo '<div class="col-sm-2">'; if ($test_time >= 0) { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<i class="bi bi-hourglass-split"></i> '; } else { echo 'time: '; } echo $test_time, ' ms'; } echo '</div>'; echo '<div class="col-sm-2">'; if ($test_memory >= 0) { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<i class="bi bi-memory"></i> '; } else { echo 'memory: '; } echo $test_memory, ' kB'; } echo '</div>'; echo '</div>'; echo '</div>'; if (!$this->styler->shouldFadeDetails($test_info)) { $accordion_collapse_class = 'card-collapse collapse'; if ($this->styler->collapse_in) { $accordion_collapse_class .= ' in'; } echo '<div id="', $accordion_collapse, '" class="uoj-testcase ', $accordion_collapse_class, '" data-test=' . $test_num . '>'; echo '<div class="card-body">'; $this->_print_c($node); echo '</div>'; echo '</div>'; } echo '</div>'; } elseif ($node->nodeName == 'custom-test') { $test_info = $node->getAttribute('info'); $test_time = $node->getAttribute('time'); $test_memory = $node->getAttribute('memory'); echo '<div class="card ', $this->styler->getTestInfoClass($test_info); if (isset($REQUIRE_LIB['bootstrap5'])) { } else { } echo ' mb-3">'; $accordion_parent = "{$this->name}_details_accordion"; $accordion_collapse = "{$accordion_parent}_collapse_custom_test"; echo '<div class="card-header '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' uoj-submission-result-item bg-transparent rounded-0 border-0 '; } echo '" '; if (!$this->styler->shouldFadeDetails($test_info)) { if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' data-bs-toggle="collapse" data-bs-parent="#', $accordion_parent, '" data-bs-target="#', $accordion_collapse, '" '; } else { echo ' data-toggle="collapse" data-parent="#', $accordion_parent, '" data-target="#', $accordion_collapse, '" '; } } echo '>'; echo '<div class="row">'; echo '<div class="col-sm-4">'; echo '<h4 class="card-title">', 'Custom Test: ', '</h4>'; echo '</div>'; if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<div class="col-sm-4 uoj-status-text">'; echo $this->styler->getTestInfoIcon($test_info); } else { echo '<div class="col-sm-4">'; } echo htmlspecialchars($test_info); echo '</div>'; echo '<div class="col-sm-2">'; if ($test_time >= 0) { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<i class="bi bi-hourglass-split"></i> '; } else { echo 'time: '; } echo $test_time, ' ms'; } echo '</div>'; echo '<div class="col-sm-2">'; if ($test_memory >= 0) { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<i class="bi bi-memory"></i> '; } else { echo 'memory: '; } echo $test_memory, ' kB'; } echo '</div>'; echo '</div>'; echo '</div>'; if (!$this->styler->shouldFadeDetails($test_info)) { $accordion_collapse_class = 'card-collapse collapse'; if ($this->styler->collapse_in) { $accordion_collapse_class .= ' in'; } echo '<div id="', $accordion_collapse, '" class="', $accordion_collapse_class, '">'; echo '<div class="card-body">'; $this->_print_c($node); echo '</div>'; echo '</div>'; echo '</div>'; } } elseif ($node->nodeName == 'in') { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<h4 class="fs-6 d-flex justify-content-between"><span>input: </span><a class="uoj-testcase-download-input"></a></h4>'; } else { echo '<h4>input: <a class="uoj-testcase-download-input"></a></h4>'; } echo "<pre class=\"bg-light p-3 rounded\">\n"; $this->_print_c($node); echo "\n</pre>"; } elseif ($node->nodeName == 'out') { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<h4 class="fs-6 d-flex justify-content-between"><span>output: </span><a class="uoj-testcase-download-output"></a></h4>'; } else { echo '<h4>output: <a class="uoj-testcase-download-output"></a></h4>'; } echo "<pre class=\"bg-light p-3 rounded\">\n"; $this->_print_c($node); echo "\n</pre>"; } elseif ($node->nodeName == 'res') { if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<h4 class="fs-6 d-flex justify-content-between"><span>result: </span><a class="uoj-testcase-download-result"></a></h4>'; } else { echo '<h4>result: <a class="uoj-testcase-download-result"></a></h4>'; } echo "<pre class=\"bg-light p-3 rounded\">\n"; $this->_print_c($node); echo "\n</pre>"; } else { echo '<', $node->nodeName; foreach ($node->attributes as $attr) { echo ' ', $attr->name, '="', htmlspecialchars($attr->value), '"'; } echo '>'; $this->_print_c($node); echo '</', $node->nodeName, '>'; } } public function __construct($details, $styler, $name) { global $REQUIRE_LIB; $this->name = $name; $this->styler = $styler; $this->details = $details; $this->dom = new DOMDocument(); if (!$this->dom->loadXML($this->details)) { throw new Exception("XML syntax error"); } $this->details = ''; } public function printHTML() { global $REQUIRE_LIB; $this->subtask_num = null; $this->_print($this->dom->documentElement); } } function echoJudgementDetails($raw_details, $styler, $name) { global $REQUIRE_LIB; try { $printer = new JudgementDetailsPrinter($raw_details, $styler, $name); $printer->printHTML(); } catch (Exception $e) { echo 'Failed to show details'; } } class SubmissionDetailsStyler { public $show_score = true; public $show_small_tip = true; public $collapse_in = false; public $fade_all_details = false; public function getTestInfoClass($info) { if ($info == 'Accepted' || $info == 'Extra Test Passed') { return 'card-uoj-accepted'; } elseif ($info == 'Time Limit Exceeded') { return 'card-uoj-tle'; } elseif ($info == 'Acceptable Answer') { return 'card-uoj-acceptable-answer'; } else { return 'card-uoj-wrong'; } } public function getTestInfoIcon($test_info) { if ($test_info == 'Accepted' || $test_info == 'Extra Test Passed') { return '<i class="bi bi-check-lg"></i> '; } elseif ($test_info == 'Time Limit Exceeded') { return '<i class="bi bi-clock"></i> '; } elseif ($test_info == 'Acceptable Answer') { return '<i class="bi bi-dash-square"></i> '; } elseif ($test_info == 'Wrong Answer') { return '<i class="bi bi-x-lg"></i> '; } else { return '<i class="bi bi-slash-circle"></i> '; } } public function shouldFadeDetails($info) { return $this->fade_all_details || $info == 'Extra Test Passed'; } } class CustomTestSubmissionDetailsStyler { public $show_score = true; public $show_small_tip = false; public $collapse_in = true; public $fade_all_details = false; public $ioi_contest_is_running = false; public function getTestInfoClass($info) { if ($info == 'Success') { return 'card-uoj-accepted'; } elseif ($info == 'Time Limit Exceeded') { return 'card-uoj-tle'; } elseif ($info == 'Acceptable Answer') { return 'card-uoj-acceptable-answer'; } else { return 'card-uoj-wrong'; } } public function getTestInfoIcon($test_info) { if ($test_info == 'Success') { return '<i class="bi bi-check-lg"></i> '; } elseif ($test_info == 'Time Limit Exceeded') { return '<i class="bi bi-clock"></i> '; } elseif ($test_info == 'Acceptable Answer') { return '<i class="bi bi-dash-square"></i> '; } elseif ($test_info == 'Wrong Answer') { return '<i class="bi bi-x-lg"></i> '; } else { return '<i class="bi bi-slash-circle"></i> '; } } public function shouldFadeDetails($info) { return $this->fade_all_details; } } class HackDetailsStyler { public $show_score = false; public $show_small_tip = false; public $collapse_in = true; public $fade_all_details = false; public function getTestInfoClass($info) { if ($info == 'Accepted' || $info == 'Extra Test Passed') { return 'card-uoj-accepted'; } elseif ($info == 'Time Limit Exceeded') { return 'card-uoj-tle'; } elseif ($info == 'Acceptable Answer') { return 'card-uoj-acceptable-answer'; } else { return 'card-uoj-wrong'; } } public function getTestInfoIcon($test_info) { if ($test_info == 'Accepted' || $test_info == 'Extra Test Passed') { return '<i class="bi bi-check-lg"></i> '; } elseif ($test_info == 'Time Limit Exceeded') { return '<i class="bi bi-clock"></i> '; } elseif ($test_info == 'Acceptable Answer') { return '<i class="bi bi-dash-square"></i> '; } elseif ($test_info == 'Wrong Answer') { return '<i class="bi bi-x-lg"></i> '; } else { return '<i class="bi bi-slash-circle"></i> '; } } public function shouldFadeDetails($info) { return $this->fade_all_details; } } function echoSubmissionDetails($submission_details, $name) { global $REQUIRE_LIB; echoJudgementDetails($submission_details, new SubmissionDetailsStyler(), $name); } function echoCustomTestSubmissionDetails($submission_details, $name) { echoJudgementDetails($submission_details, new CustomTestSubmissionDetailsStyler(), $name); } function echoHackDetails($hack_details, $name) { global $REQUIRE_LIB; echoJudgementDetails($hack_details, new HackDetailsStyler(), $name); } function echoHack($hack, $config, $user) { global $REQUIRE_LIB; $problem = queryProblemBrief($hack['problem_id']); echo '<tr>'; if (!isset($config['id_hidden'])) { echo '<td><a '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' class="text-decoration-none" '; } echo ' href="/hack/', $hack['id'], '">#', $hack['id'], '</a></td>'; } if (!isset($config['submission_hidden'])) { echo '<td><a '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' class="text-decoration-none" '; } echo ' href="/submission/', $hack['submission_id'], '">#', $hack['submission_id'], '</a></td>'; } if (!isset($config['problem_hidden'])) { if ($hack['contest_id']) { echo '<td>', getContestProblemLink($problem, $hack['contest_id'], '!id_and_title'), '</td>'; } else { echo '<td>', getProblemLink($problem, '!id_and_title'), '</td>'; } } if (!isset($config['hacker_hidden'])) { echo '<td>', getUserLink($hack['hacker']), '</td>'; } if (!isset($config['owner_hidden'])) { echo '<td>', getUserLink($hack['owner']), '</td>'; } if (!isset($config['result_hidden'])) { if ($hack['judge_time'] == null) { echo '<td><a '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' class="text-decoration-none" '; } echo ' href="/hack/', $hack['id'], '">Waiting</a></td>'; } elseif ($hack['success'] == null) { echo '<td><a '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' class="text-decoration-none" '; } echo ' href="/hack/', $hack['id'], '">Judging</a></td>'; } elseif ($hack['success']) { echo '<td><a href="/hack/', $hack['id'], '" class="uoj-status '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' text-decoration-none '; } echo ' " data-success="1"><strong>Success!</strong></a></td>'; } else { echo '<td><a href="/hack/', $hack['id'], '" class="uoj-status '; if (isset($REQUIRE_LIB['bootstrap5'])) { echo ' text-decoration-none '; } echo ' " data-success="0"><strong>Failed.</strong></a></td>'; } } else { echo '<td>Hidden</td>'; } if (!isset($config['submit_time_hidden'])) { echo '<td>', $hack['submit_time'], '</td>'; } if (!isset($config['judge_time_hidden'])) { echo '<td>', $hack['judge_time'], '</td>'; } echo '</tr>'; } function echoHackListOnlyOne($hack, $config, $user) { global $REQUIRE_LIB; if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<div class="card mb-3 table-responsive">'; echo '<table class="table text-center uoj-table mb-0">'; } else { echo '<div class="table-responsive">'; echo '<table class="table table-bordered table-text-center">'; } echo '<thead>'; echo '<tr>'; if (!isset($config['id_hidden'])) { echo '<th>ID</th>'; } if (!isset($config['submission_id_hidden'])) { echo '<th>'.UOJLocale::get('problems::submission id').'</th>'; } if (!isset($config['problem_hidden'])) { echo '<th>'.UOJLocale::get('problems::problem').'</th>'; } if (!isset($config['hacker_hidden'])) { echo '<th>'.UOJLocale::get('problems::hacker').'</th>'; } if (!isset($config['owner_hidden'])) { echo '<th>'.UOJLocale::get('problems::owner').'</th>'; } if (!isset($config['result_hidden'])) { echo '<th>'.UOJLocale::get('problems::result').'</th>'; } if (!isset($config['submit_time_hidden'])) { echo '<th>'.UOJLocale::get('problems::submit time').'</th>'; } if (!isset($config['judge_time_hidden'])) { echo '<th>'.UOJLocale::get('problems::judge time').'</th>'; } echo '</tr>'; echo '</thead>'; echo '<tbody>'; echoHack($hack, $config, $user); echo '</tbody>'; echo '</table>'; echo '</div>'; } function echoHacksList($cond, $tail, $config, $user) { $header_row = '<tr>'; $col_names = array(); $col_names[] = 'id'; $col_names[] = 'success'; $col_names[] = 'judge_time'; if (!isset($config['id_hidden'])) { $header_row .= '<th>ID</th>'; } if (!isset($config['submission_id_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::submission id').'</th>'; $col_names[] = 'submission_id'; } if (!isset($config['problem_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::problem').'</th>'; $col_names[] = 'problem_id'; } if (!isset($config['hacker_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::hacker').'</th>'; $col_names[] = 'hacker'; } if (!isset($config['owner_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::owner').'</th>'; $col_names[] = 'owner'; } if (!isset($config['result_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::result').'</th>'; } if (!isset($config['submit_time_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::submit time').'</th>'; $col_names[] = 'submit_time'; } if (!isset($config['judge_time_hidden'])) { $header_row .= '<th>'.UOJLocale::get('problems::judge time').'</th>'; } $header_row .= '</tr>'; if (!isSuperUser($user)) { if ($user != null) { $permission_cond = "is_hidden = false or (is_hidden = true and problem_id in (select problem_id from problems_permissions where username = '{$user['username']}'))"; } else { $permission_cond = "is_hidden = false"; } if ($cond !== '1') { $cond = "($cond) and ($permission_cond)"; } else { $cond = $permission_cond; } } $table_config = isset($config['table_config']) ? $config['table_config'] : null; echoLongTable($col_names, 'hacks', $cond, $tail, $header_row, function($hacks) use ($config, $user) { echoHack($hacks, $config, $user); }, $table_config); } function echoBlog($blog, $config = array()) { global $REQUIRE_LIB; $default_config = array( 'blog' => $blog, 'show_title_only' => false, 'is_preview' => false ); foreach ($default_config as $key => $val) { if (!isset($config[$key])) { $config[$key] = $val; } } $config['REQUIRE_LIB'] = $REQUIRE_LIB; uojIncludeView('blog-preview', $config); } function echoBlogTag($tag) { global $REQUIRE_LIB; if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<a class="uoj-blog-tag my-1">'; echo '<span class="badge bg-secondary">'; } else { echo '<a class="uoj-blog-tag">'; echo '<span class="badge badge-pill badge-secondary">'; } echo HTML::escape($tag), '</span></a>'; } function echoUOJPageHeader($page_title, $extra_config = array()) { global $REQUIRE_LIB; $config = UOJContext::pageConfig(); $config['REQUIRE_LIB'] = $REQUIRE_LIB; $config['PageTitle'] = $page_title; $config = array_merge($config, $extra_config); uojIncludeView('page-header', $config); } function echoUOJPageFooter($config = array()) { global $REQUIRE_LIB; $config['REQUIRE_LIB'] = $REQUIRE_LIB; uojIncludeView('page-footer', $config); } function echoRanklist($config = array()) { global $REQUIRE_LIB; $header_row = ''; $header_row .= '<tr>'; $header_row .= '<th style="width: 5em;">#</th>'; $header_row .= '<th style="width: 14em;">'.UOJLocale::get('username').'</th>'; $header_row .= '<th style="width: 50em;">'.UOJLocale::get('motto').'</th>'; $header_row .= '<th style="width: 5em;">'.UOJLocale::get('solved').'</th>'; $header_row .= '</tr>'; $parsedown = HTML::parsedown(); $purifier = HTML::purifier_inline(); $users = array(); $print_row = function($user, $now_cnt) use (&$users, $config, $purifier, $parsedown) { if (!$users) { if ($now_cnt == 1) { $rank = 1; } else { $rank = DB::selectCount("select count(*) from (select b.username as username, count(*) as accepted from best_ac_submissions a inner join user_info b on a.submitter = b.username group by username) as derived where accepted > {$user['ac_num']}") + 1; } } else { $rank = $now_cnt; } $user['rank'] = $rank; echo '<tr>'; echo '<td>' . $user['rank'] . '</td>'; echo '<td>' . getUserLink($user['username']) . '</td>'; echo "<td>"; echo $purifier->purify($parsedown->line($user['motto'])); echo "</td>"; echo '<td>' . $user['ac_num'] . '</td>'; echo '</tr>'; $users[] = $user; }; $from = 'best_ac_submissions a inner join user_info b on a.submitter = b.username'; $col_names = array('b.username as username', 'count(*) as ac_num', 'b.motto as motto'); $cond = '1'; $tail = 'group by username order by ac_num desc, username asc'; if (isset($config['group_id'])) { $group_id = $config['group_id']; $from = "best_ac_submissions a inner join user_info b on a.submitter = b.username inner join groups_users c on (a.submitter = c.username and c.group_id = {$group_id})"; } if (isset($config['top10'])) { $tail .= ' limit 10'; } $config['get_row_index'] = ''; $config['pagination_table'] = 'user_info'; echoLongTable($col_names, $from, $cond, $tail, $header_row, $print_row, $config); }