1<?php 2 3/* 4 Phoronix Test Suite 5 URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/ 6 Copyright (C) 2015, Phoronix Media 7 Copyright (C) 2015, Michael Larabel 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23 24class phoromatic_benchmark implements pts_webui_interface 25{ 26 public static function page_title() 27 { 28 return 'One-Time Benchmark Run'; 29 } 30 public static function page_header() 31 { 32 return null; 33 } 34 public static function preload($PAGE) 35 { 36 return true; 37 } 38 public static function render_page_process($PATH) 39 { 40 if(PHOROMATIC_USER_IS_VIEWER) 41 return; 42 43 $is_new = true; 44 if(!empty($PATH[0]) && $PATH[0] == 'all') 45 { 46 $main = '<h1>Past Benchmark Tickets</h1>'; 47 $stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_benchmark_tickets WHERE AccountID = :account_id AND State >= 0 ORDER BY TicketIssueTime DESC'); 48 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 49 $result = $stmt->execute(); 50 $main .= '<ol>'; 51 52 if($result) 53 { 54 $row = $result->fetchArray(); 55 56 if(!empty($row)) 57 { 58 do 59 { 60 $main .= '<li><a href="?benchmark/' . $row['TicketID'] . '">' . $row['Title'] . '</a></li>'; 61 } 62 while($row = $result->fetchArray()); 63 } 64 } 65 else 66 { 67 $main .= '<li>No Benchmark Tickets Found</li>'; 68 } 69 70 $main .= '</ol>'; 71 } 72 else if(!empty($PATH[0]) && is_numeric($PATH[0])) 73 { 74 $stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_benchmark_tickets WHERE AccountID = :account_id AND TicketID = :ticket_id'); 75 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 76 $stmt->bindValue(':ticket_id', $PATH[0]); 77 $result = $stmt->execute(); 78 $row = $result->fetchArray(); 79 80 if(!empty($row)) 81 { 82 if(isset($_GET['remove'])) 83 { 84 $stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_benchmark_tickets WHERE AccountID = :account_id AND TicketID = :ticket_id'); 85 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 86 $stmt->bindValue(':ticket_id', $PATH[0]); 87 $result = $stmt->execute(); 88 header('Location: /?benchmark'); 89 } 90 else if(isset($_GET['repeat'])) 91 { 92 $stmt = phoromatic_server::$db->prepare('UPDATE phoromatic_benchmark_tickets SET TicketIssueTime = :new_ticket_time, State = 1 WHERE AccountID = :account_id AND TicketID = :ticket_id'); 93 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 94 $stmt->bindValue(':ticket_id', $PATH[0]); 95 $stmt->bindValue(':new_ticket_time', time()); 96 $result = $stmt->execute(); 97 } 98 else if(isset($_GET['disable'])) 99 { 100 $stmt = phoromatic_server::$db->prepare('UPDATE phoromatic_benchmark_tickets SET State = 0 WHERE AccountID = :account_id AND TicketID = :ticket_id'); 101 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 102 $stmt->bindValue(':ticket_id', $PATH[0]); 103 $result = $stmt->execute(); 104 } 105 106 $main = null; 107 $main .= '<h1>' . $row['Title'] . '</h1>'; 108 $main .= '<h3>' . $row['Description'] . '</h3>'; 109 $main .= '<p>This benchmark ticket was created on <strong>' . date('j F Y \a\t H:i', strtotime($row['LastModifiedOn'])) . '</strong> by <strong>' . $row['LastModifiedBy'] . '. The ticket was last issued for testing at ' . date('j F Y \a\t H:i', $row['TicketIssueTime']) . '</strong>.'; 110 $main .= '<p> <a href="/?benchmark/' . $PATH[0] . '/&repeat">Repeat Ticket</a> <a href="/?benchmark/' . $PATH[0] . '/&remove">Remove Ticket</a>' . (!isset($_GET['disable']) && $row['State'] > 0 ? ' <a href="/?benchmark/' . $PATH[0] . '/&disable">End Ticket</a>' : null) . '</p>'; 111 112 if(!empty($row['RunTargetSystems'])) 113 { 114 $main .= '<hr /><h1>System Targets</h1><ol>'; 115 foreach(explode(',', $row['RunTargetSystems']) as $system_id) 116 { 117 $main .= '<li><a href="?systems/' . $system_id . '">' . phoromatic_server::system_id_to_name($system_id) . '</a></li>'; 118 } 119 } 120 if(!empty($row['RunTargetGroups'])) 121 { 122 $main .= '<hr /><h1>Group Targets</h1><ol>'; 123 foreach(explode(',', $row['RunTargetGroups']) as $group) 124 { 125 if(empty($group)) 126 continue; 127 128 $main .= '<li><strong style="font-weight: 800;">' . $group . '</strong></li>'; 129 130 $stmt = phoromatic_server::$db->prepare('SELECT SystemID FROM phoromatic_systems WHERE AccountID = :account_id AND Groups LIKE :sgroup AND State > 0 ORDER BY Title ASC'); 131 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 132 $stmt->bindValue(':sgroup', '%#' . $group . '#%'); 133 $result = $stmt->execute(); 134 135 while($result && $row = $result->fetchArray()) 136 { 137 $main .= '<li><a href="?systems/' . $row['SystemID'] . '">' . phoromatic_server::system_id_to_name($row['SystemID']) . '</a></li>'; 138 } 139 } 140 } 141 142 $main .= '</ol>'; 143 144 if(!empty($row['EnvironmentVariables'])) 145 { 146 $main .= '<hr /><h1>Environment</h1><ol>'; 147 148 foreach(explode(';', $row['EnvironmentVariables']) as $env) 149 { 150 $main .= '<li><strong>' . $env . '</strong></li>'; 151 } 152 $main .= '</ol>'; 153 } 154 155 $main .= '<hr /><h1>Ticket Payload</h1>'; 156 $main .= '<p>This ticket runs the <strong>' . $row['SuiteToRun'] . '</strong> test suite:</p>'; 157 $main .= '<div style="max-height: 400px; overflow-y: scroll;">'; 158 $xml_path = phoromatic_server::phoromatic_account_suite_path($_SESSION['AccountID'], $row['SuiteToRun']) . 'suite-definition.xml'; 159 if(is_file($xml_path)) 160 { 161 $test_suite = new pts_test_suite($xml_path); 162 163 // $main .= '<h2>' . $test_suite->get_title() . '</h2>'; 164 // $main .= '<p><strong>' . $test_suite->get_maintainer() . '</strong></p>'; 165 // $main .= '<p><em>' . $test_suite->get_description() . '</em></p>'; 166 167 foreach($test_suite->get_contained_test_result_objects() as $tro) 168 { 169 $main .= '<h3>' . $tro->test_profile->get_title() . ' [' . $tro->test_profile->get_identifier() . ']</h3>'; 170 $main .= '<p>' . $tro->get_arguments_description() . '</p>'; 171 } 172 173 //$main .= '<hr />'; 174 } 175 176 $main .= '</div><hr />'; 177 $main .= '<div class="pts_phoromatic_info_box_area">'; 178 if(strpos($row['EnvironmentVariables'], 'PTS_CONCURRENT_TEST_RUNS') !== false) 179 { 180 if(isset($_REQUEST['view_log']) && is_file(phoromatic_server::phoromatic_account_stress_log_path($_SESSION['AccountID'], $PATH[0]) . $_REQUEST['view_log'] . '.log')) 181 { 182 $main .= '<hr /><h1>Stress Log For: ' . phoromatic_server::system_id_to_name($_REQUEST['view_log']) . '</h1>'; 183 $log_text = PHP_EOL . file_get_contents(phoromatic_server::phoromatic_account_stress_log_path($_SESSION['AccountID'], $PATH[0]) . $_REQUEST['view_log'] . '.log'); 184 185 $x = 0; 186 while(($x = strpos($log_text, "\n##", $x)) !== false) 187 { 188 $log_text = substr($log_text, 0, $x) . "\n<strong style=\"font-weight: 800;\">" . substr($log_text, $x + 1); 189 190 if(($y = strpos($log_text, "\n", $x + 2)) !== false) 191 { 192 $log_text = substr($log_text, 0, $y) . '</strong>' . substr($log_text, $y); 193 } 194 $x = $y; 195 } 196 197 $x = 0; 198 while(($x = strpos($log_text, "\n[", $x)) !== false) 199 { 200 $log_text = substr($log_text, 0, $x) . "\n<strong style=\"font-weight: 800;\">" . substr($log_text, $x + 1); 201 202 if(($y = strpos($log_text, "]", $x + 2)) !== false) 203 { 204 $log_text = substr($log_text, 0, $y) . '</strong>' . substr($log_text, $y); 205 } 206 $x = $y; 207 } 208 $main .= '<blockquote>' . str_replace("\n", '<br />', $log_text) . '</blockquote>'; 209 $main .= '<p><a href="?benchmark/' . $PATH[0] . '#stress_logs">View Other System Logs</a></p>'; 210 } 211 else 212 { 213 $main .= '<a name="stress_logs"></a><hr /><h1>Stress Run Logs</h1><ol>'; 214 $count = 0; 215 foreach(pts_file_io::glob(phoromatic_server::phoromatic_account_stress_log_path($_SESSION['AccountID'], $PATH[0]) . '*.log') as $log_file) 216 { 217 $sys_id = basename($log_file, '.log'); 218 $main .= '<li><a href="?benchmark/' . $PATH[0] . '/&view_log=' . $sys_id . '">' . phoromatic_server::system_id_to_name($sys_id) . '</a></li>'; 219 $count++; 220 } 221 if($count == 0) 222 { 223 $main .= '<li><em>No Logs Currently Available</em></li>'; 224 } 225 $main .= '</ol>'; 226 } 227 } 228 else 229 { 230 $main .= '<div style="margin: 0 5%;"><ul style="max-height: 100%;"><li><h1>Test Results</h1></li>'; 231 $stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed FROM phoromatic_results WHERE AccountID = :account_id AND BenchmarkTicketID = :ticket_id ORDER BY UploadTime DESC'); 232 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 233 $stmt->bindValue(':ticket_id', $PATH[0]); 234 $test_result_result = $stmt->execute(); 235 $results = 0; 236 while($test_result_row = $test_result_result->fetchArray()) 237 { 238 $main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'?result/' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td>' . phoromatic_system_id_to_name($test_result_row['SystemID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) . '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>'; 239 $results++; 240 241 } 242 if($results == 0) 243 { 244 $main .= '<li class="light" style="text-align: center;">No Results Found</li>'; 245 } 246 else if($results > 3) 247 { 248 $main .= '<a onclick=""><li id="global_bottom_totals"><input type="checkbox" id="global_checkbox" onclick="javascript:phoromatic_toggle_checkboxes_on_page(this);" onchange="return false;"></input> <strong>' . $results . ' Results</strong></li></a>'; 249 } 250 $main .= '</ul></div>'; 251 $main .= '</div>'; 252 } 253 } 254 } 255 else 256 { 257 if(isset($_POST['benchmark_title']) && !empty($_POST['benchmark_title'])) 258 { 259 $title = phoromatic_get_posted_var('benchmark_title'); 260 $description = phoromatic_get_posted_var('benchmark_description'); 261 $result_identifier = phoromatic_get_posted_var('benchmark_identifier'); 262 $suite_to_run = phoromatic_get_posted_var('suite_to_run'); 263 264 if(strlen($title) < 3) 265 { 266 echo '<h2>Title must be at least three characters.</h2>'; 267 exit; 268 } 269 if(strlen($result_identifier) < 3) 270 { 271 echo '<h2>Identifier must be at least three characters.</h2>'; 272 exit; 273 } 274 if(strlen($suite_to_run) < 3) 275 { 276 echo '<h2>You must specify a suite to run.</h2>'; 277 exit; 278 } 279 280 $run_target_systems = phoromatic_get_posted_var('run_on_systems', array()); 281 $run_target_groups = phoromatic_get_posted_var('run_on_groups', array()); 282 if(!is_array($run_target_systems)) $run_target_systems = array(); 283 if(!is_array($run_target_groups)) $run_target_groups = array(); 284 $run_target_systems = implode(',', $run_target_systems); 285 $run_target_groups = implode(',', $run_target_groups); 286 287 if($is_new) 288 { 289 do 290 { 291 $ticket_id = rand(10, 999999); 292 $matching_tickets = phoromatic_server::$db->querySingle('SELECT TicketID FROM phoromatic_benchmark_tickets WHERE TicketID = \'' . $ticket_id . '\''); 293 } 294 while(!empty($matching_tickets)); 295 } 296 297 $env_vars = array(); 298 299 if(is_numeric($_POST['PTS_CONCURRENT_TEST_RUNS']) && $_POST['PTS_CONCURRENT_TEST_RUNS'] > 0) 300 { 301 array_push($env_vars, 'PTS_CONCURRENT_TEST_RUNS=' . $_POST['PTS_CONCURRENT_TEST_RUNS']); 302 } 303 if(is_numeric($_POST['TOTAL_LOOP_TIME']) && $_POST['TOTAL_LOOP_TIME'] > 0) 304 { 305 array_push($env_vars, 'TOTAL_LOOP_TIME=' . $_POST['TOTAL_LOOP_TIME']); 306 } 307 308 $env_vars = implode(';', $env_vars); 309 310 // Add benchmark 311 $stmt = phoromatic_server::$db->prepare('INSERT OR REPLACE INTO phoromatic_benchmark_tickets (AccountID, TicketID, TicketIssueTime, Title, ResultIdentifier, SuiteToRun, Description, State, LastModifiedBy, LastModifiedOn, RunTargetGroups, RunTargetSystems, EnvironmentVariables) VALUES (:account_id, :ticket_id, :ticket_time, :title, :result_identifier, :suite_to_run, :description, :state, :modified_by, :modified_on, :run_target_groups, :run_target_systems, :environment_variables)'); 312 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 313 $stmt->bindValue(':ticket_id', $ticket_id); 314 $stmt->bindValue(':ticket_time', time()); 315 $stmt->bindValue(':title', $title); 316 $stmt->bindValue(':result_identifier', $result_identifier); 317 $stmt->bindValue(':suite_to_run', $suite_to_run); 318 $stmt->bindValue(':description', $description); 319 $stmt->bindValue(':state', 1); 320 $stmt->bindValue(':modified_by', $_SESSION['UserName']); 321 $stmt->bindValue(':modified_on', phoromatic_server::current_time()); 322 $stmt->bindValue(':public_key', isset($public_key) ? $public_key : null); 323 $stmt->bindValue(':run_target_groups', $run_target_groups); 324 $stmt->bindValue(':run_target_systems', $run_target_systems); 325 $stmt->bindValue(':environment_variables', $env_vars); 326 $result = $stmt->execute(); 327 phoromatic_add_activity_stream_event('benchmark', $ticket_id, ($is_new ? 'added' : 'modified')); 328 329 if($result) 330 { 331 header('Location: ?benchmark/' . $ticket_id); 332 } 333 } 334 335 $main = ' 336 <h2>' . ($is_new ? 'Create' : 'Edit') . ' A Benchmark</h2> 337 <p>This page allows you to run a test suite -- consisting of a single or multiple test suites -- on a given set/group of systems right away at their next earliest possibility. This benchmark mode is an alternative to the <a href="?schedules">benchmark schedules</a> for reptitive/routine testing.</p>'; 338 339 $local_suites = pts_file_io::glob(phoromatic_server::phoromatic_account_suite_path($_SESSION['AccountID']) . '*/suite-definition.xml'); 340 341 if(empty($local_suites)) 342 { 343 $main .= '<p><strong>Before you can create a benchmark ticket you must first <a href="?build_suite">create a test suite</a> with the tests you wish to run.</strong></p>'; 344 } 345 else 346 { 347 $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="run_benchmark" id="run_benchmark" method="post" enctype="multipart/form-data" onsubmit="return validate_run_benchmark();"> 348 <h3>Title:</h3> 349 <p>The title is the name of the result file for this test run.</p> 350 <p><input type="text" name="benchmark_title" value="' . (!$is_new ? $e_schedule['Title'] : null) . '" /></p> 351 <h3>Test Run Identifier:</h3> 352 <p>The test run identifier is the per-system name for the system(s) being benchmarked. The following variables may be used: <strong>.SYSTEM</strong>, <strong>.GROUP</strong>. Any custom per-user system variables set via the individual system pages can also be used.</p> 353 <p><input type="text" name="benchmark_identifier" value="' . (!$is_new ? $e_schedule['Identifier'] : null) . '" /></p> 354 <h3>Test Suite To Run:</h3> 355 <p><a href="?build_suite">Build a suite</a> to add/select more tests to run or <a href="?local_suites">view local suites</a> for more information on a particular suite. A test suite is a set of test profiles to run in a pre-defined manner.</p>'; 356 $main .= '<p><select name="suite_to_run">'; 357 foreach($local_suites as $xml_path) 358 { 359 $id = basename(dirname($xml_path)); 360 $test_suite = new pts_test_suite($xml_path); 361 $main .= '<option value="' . $id . '">' . $test_suite->get_title() . ' - ' . $id . '</option>'; 362 } 363 $main .= '</select></p>'; 364 $main .= '<h3>Description:</h3> 365 <p>The description is an optional way to add more details about the intent or objective of this test run.</p> 366 <p><textarea name="benchmark_description" id="benchmark_description" cols="50" rows="3">' . (!$is_new ? $e_schedule['Description'] : null) . '</textarea></p> 367 <hr /><h3>System Targets:</h3> 368 <p>Select the systems that should be benchmarked at their next earliest convenience.</p> 369 <p style="white-space: nowrap;">'; 370 371 $stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID FROM phoromatic_systems WHERE AccountID = :account_id AND State >= 0 ORDER BY Title ASC'); 372 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 373 $result = $stmt->execute(); 374 375 376 if(!$is_new) 377 { 378 $e_schedule['RunTargetSystems'] = explode(',', $e_schedule['RunTargetSystems']); 379 $e_schedule['RunTargetGroups'] = explode(',', $e_schedule['RunTargetGroups']); 380 } 381 382 if($row = $result->fetchArray()) 383 { 384 $main .= '<h4>Systems: '; 385 do 386 { 387 $main .= '<input type="checkbox" name="run_on_systems[]" value="' . $row['SystemID'] . '" ' . (!$is_new && in_array($row['SystemID'], $e_schedule['RunTargetSystems']) ? 'checked="checked" ' : null) . '/> ' . $row['Title'] . ' '; 388 } 389 while($row = $result->fetchArray()); 390 $main .= '</h4>'; 391 } 392 393 $stmt = phoromatic_server::$db->prepare('SELECT GroupName FROM phoromatic_groups WHERE AccountID = :account_id ORDER BY GroupName ASC'); 394 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 395 $result = $stmt->execute(); 396 397 if($row = $result->fetchArray()) 398 { 399 $main .= '<h4>Groups: '; 400 do 401 { 402 $main .= '<input type="checkbox" name="run_on_groups[]" value="' . $row['GroupName'] . '" ' . (!$is_new && in_array($row['GroupName'], $e_schedule['RunTargetGroups']) ? 'checked="checked" ' : null) . '/> ' . $row['GroupName'] . ' '; 403 } 404 while($row = $result->fetchArray()); 405 $main .= '</h4>'; 406 } 407 408 $main .= '</p> 409 <hr /><h3>Environment Options</h3> 410 <h4>Stress Testing</h4> 411 <p>If you wish to test systems for stability/reliability rather than performance, use this option and specify the number of tests to run concurrently (two or more) and (optionally) for the total period of time to continue looping the benchmarks. These options are intended to just stress the system and will not record any benchmark results. From the command-line this testing mode can be used via the <em>phoronix-test-suite stress-run</em> sub-command.</p> 412 <p><strong>Concurrent Number Of Test Processes:</strong> <select name="PTS_CONCURRENT_TEST_RUNS"><option value="0">Disabled</option>'; 413 for($i = 2; $i <= 24; $i++) 414 { 415 $main .= '<option value="' . $i . '">' . $i . '</option>'; 416 } 417 $main .= '</select></p> 418 <p><strong>Force Loop Time:</strong> <select name="TOTAL_LOOP_TIME"><option value="0">Disabled</option>'; 419 $s = true; 420 for($i = 5; $i < 60; $i += 5) 421 { 422 if($i > 15 && $i % 10 != 0) 423 { 424 continue; 425 } 426 $main .= '<option value="' . $i . '">' . pts_strings::format_time($i, 'MINUTES') . '</option>'; 427 } 428 for($i = 60; $i <= (30 * 24 * 60); $i += 60) 429 { 430 if($i > 10080) 431 { 432 // 7 days 433 if(($i % 1440) != 0) 434 continue; 435 } 436 else if($i > 480) 437 { 438 $s = !$s; 439 if(!$s) 440 continue; 441 } 442 443 $main .= '<option value="' . $i . '">' . pts_strings::format_time($i, 'MINUTES') . '</option>'; 444 } 445 $main .= '</select></p>'; 446 447 /* $main .= '<h4>System Monitoring</h4> 448 <p>The Phoronix Test Suite system monitor module allows for select hardware/software sensors to be logged in real-time while running the selected test suite. The supported sensors are then shown within the result file upon the test\'s completion.</p>'; 449 450 foreach(phodevi::available_sensors() as $sensor) 451 { 452 $main .= '<input type="checkbox" name="MONITOR" value="' . phodevi::sensor_identifier($sensor) . '" /> ' . phodevi::sensor_name($sensor) . ' '; 453 } 454*/ 455 $main .= '<hr /><p align="left"><input name="submit" value="' . ($is_new ? 'Run' : 'Edit') . ' Benchmark" type="submit" onclick="return pts_rmm_validate_schedule();" /></p> 456 </form>'; 457 } 458 } 459 460 $stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_benchmark_tickets WHERE AccountID = :account_id AND State >= 0 AND TicketIssueTime > :time_cutoff ORDER BY TicketIssueTime DESC LIMIT 30'); 461 $stmt->bindValue(':account_id', $_SESSION['AccountID']); 462 $stmt->bindValue(':time_cutoff', (time() - (60 * 60 * 24 * 14))); 463 $result = $stmt->execute(); 464 $right = '<ul><li>Benchmark Tickets</li>'; 465 466 if($result) 467 { 468 $row = $result->fetchArray(); 469 470 if(!empty($row)) 471 { 472 do 473 { 474 $right .= '<li><a href="?benchmark/' . $row['TicketID'] . '">' . $row['Title'] . '</a></li>'; 475 } 476 while($row = $result->fetchArray()); 477 } 478 } 479 $right .= '<li><em><a href="?benchmark/all">View All Past Tickets</a></em></li>'; 480 $right .= '</ul>'; 481 482 echo phoromatic_webui_header_logged_in(); 483 echo phoromatic_webui_main($main, phoromatic_webui_right_panel_logged_in($right)); 484 echo phoromatic_webui_footer(); 485 } 486} 487 488?> 489