1<?php
2/*
3	Phoronix Test Suite
4	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
5	Copyright (C) 2019 - 2021, Phoronix Media
6	Copyright (C) 2019 - 2021, Michael Larabel
7
8	This program is free software; you can redistribute it and/or modify
9	it under the terms of the GNU General Public License as published by
10	the Free Software Foundation; either version 3 of the License, or
11	(at your option) any later version.
12
13	This program is distributed in the hope that it will be useful,
14	but WITHOUT ANY WARRANTY; without even the implied warranty of
15	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16	GNU General Public License for more details.
17
18	You should have received a copy of the GNU General Public License
19	along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22error_reporting(E_ALL);
23if(function_exists('session_start'))
24{
25	session_start();
26}
27
28define('CURRENT_URI', $_SERVER['REQUEST_URI']);
29define('WEB_URL_PATH', rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])), '/') . '/');
30define('RESULT_VIEWER_VERSION', 2);
31define('PTS_AUTO_LOAD_ALL_OBJECTS', true);
32
33$uri_stripped = CURRENT_URI;
34if(($x = strpos($uri_stripped, '&')) !== false)
35{
36	$args = substr($uri_stripped, $x + 1);
37	$r = array();
38	parse_str($args, $r);
39	$_REQUEST = array_merge($r, $_REQUEST);
40	$uri_stripped = substr($uri_stripped, 0, $x);
41}
42
43if(isset($_REQUEST['checkbox_compare_results']))
44{
45	echo '<script> window.location.href = "http://' . $_SERVER['HTTP_HOST'] . WEB_URL_PATH . 'result/' . implode(',', $_REQUEST['checkbox_compare_results']) . '"; </script>';
46	exit;
47}
48$uri_segments = explode('/', trim((WEB_URL_PATH == '/' ? $uri_stripped : str_replace(WEB_URL_PATH, '', $uri_stripped)), '/'));
49switch((isset($uri_segments[0]) ? $uri_segments[0] : null))
50{
51	case 'result':
52		$_GET['page'] = 'result';
53		$_GET['result'] = $uri_segments[1];
54		break;
55	case 'test':
56		$_GET['page'] = 'test';
57		$_GET['test'] = base64_decode($uri_segments[1]);
58		break;
59	case 'suite':
60		$_GET['page'] = 'suite';
61		$_GET['suite'] = base64_decode($uri_segments[1]);
62		break;
63	case 'tests':
64	case 'suites':
65		$_GET['page'] = $uri_segments[0];
66		break;
67}
68
69if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && isset($_ENV['TEMP']) && is_file($_ENV['TEMP'] . '\pts-env-web'))
70{
71	foreach(explode(PHP_EOL,  file_get_contents($_ENV['TEMP'] . '\pts-env-web')) as $line)
72	{
73		if(!empty($line))
74		{
75			putenv($line);
76		}
77	}
78}
79
80if(getenv('PTS_VIEWER_RESULT_PATH') && getenv('PTS_VIEWER_PTS_PATH'))
81{
82	define('VIEWER_ACCESS_KEY', getenv('PTS_VIEWER_ACCESS_KEY'));
83	define('PTS_SAVE_RESULTS_PATH', getenv('PTS_VIEWER_RESULT_PATH'));
84	define('VIEWER_PHORONIX_TEST_SUITE_PATH', getenv('PTS_VIEWER_PTS_PATH'));
85}
86else
87{
88	if(!is_file('result_viewer_config.php'))
89	{
90		echo '<p>You must configure result_viewer_config.php!</p>';
91		echo '<p>Current debug values: PTS_VIEWER_RESULT_PATH = ' . getenv('PTS_VIEWER_RESULT_PATH') . ' PTS_VIEWER_PTS_PATH = ' . getenv('PTS_VIEWER_PTS_PATH') . '</p>';
92		exit;
93	}
94	require('result_viewer_config.php');
95}
96
97define('PTS_MODE', 'LIB');
98define('PTS_AUTO_LOAD_OBJECTS', true);
99
100if(!is_file(VIEWER_PHORONIX_TEST_SUITE_PATH . '/pts-core/pts-core.php'))
101{
102	echo '<p>Could not find: ' . VIEWER_PHORONIX_TEST_SUITE_PATH . '/pts-core/pts-core.php</p>';
103	exit;
104}
105require(VIEWER_PHORONIX_TEST_SUITE_PATH . '/pts-core/pts-core.php');
106pts_define_directories();
107
108set_time_limit(60);
109ini_set('memory_limit','2048M');
110
111if(isset($_GET['PTS']))
112{
113	// Test for client to see if resolving properly
114	echo 'PTS';
115	exit;
116}
117
118define('CSS_RESULT_VIEWER_PATH', str_replace('//', '/', WEB_URL_PATH . '/result-viewer.css?' . PTS_CORE_VERSION));
119
120if(!defined('PTS_CORE_STORAGE') && getenv('PTS_CORE_STORAGE') && is_file(getenv('PTS_CORE_STORAGE')))
121{
122	define('PTS_CORE_STORAGE',  getenv('PTS_CORE_STORAGE'));
123}
124
125pts_config::set_override_default_config(getenv('PTS_VIEWER_CONFIG_FILE'));
126if(PTS_SAVE_RESULTS_PATH && is_writable(PTS_SAVE_RESULTS_PATH) && getenv('PTS_VIEWER_CONFIG_FILE'))
127{
128	define('VIEWER_CAN_MODIFY_RESULTS', pts_config::read_bool_config('PhoronixTestSuite/Options/ResultViewer/AllowSavingResultChanges', 'FALSE'));
129	define('VIEWER_CAN_DELETE_RESULTS', pts_config::read_bool_config('PhoronixTestSuite/Options/ResultViewer/AllowDeletingResults', 'FALSE'));
130}
131else
132{
133	define('VIEWER_CAN_MODIFY_RESULTS', false);
134	define('VIEWER_CAN_DELETE_RESULTS', false);
135}
136
137
138// Authenticate user and set session variables
139if(isset($_POST['access_key']))
140{
141	if(function_exists('hash'))
142	{
143		$_SESSION['AccessKey'] = trim(hash('sha256', trim($_POST['access_key'])));
144	}
145	else
146	{
147		$_SESSION['AccessKey'] = trim(sha1(trim($_POST['access_key'])));
148	}
149}
150
151if(VIEWER_ACCESS_KEY != null && (!isset($_SESSION['AccessKey']) || $_SESSION['AccessKey'] != VIEWER_ACCESS_KEY)) { ?>
152<!doctype html>
153<html lang="en">
154<head>
155  <title>Phoronix Test Suite - Result Portal</title>
156<link rel="stylesheet" href="<?php echo CSS_RESULT_VIEWER_PATH; ?>">
157<script type="text/javascript" src="<?php echo WEB_URL_PATH; ?>/result-viewer.js?<?php echo PTS_CORE_VERSION; ?>"></script>
158<link href="//fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
159<link rel="icon" type="image/png" href="<?php echo WEB_URL_PATH; ?>favicon.png">
160</head>
161<body>
162
163<div id="login_box">
164<div id="login_box_left">
165<h1>Phoronix Test Suite</h1>
166<h2>Result Portal</h2>
167</div>
168<div id="login_box_right">
169<form name="login_form" id="login_form" action="<?php echo CURRENT_URI; ?>" method="post"><br />
170<input type="password" name="access_key" id="u_access_key" required placeholder="Access Key" /><br />
171<input type="submit" value="Login" />
172</form>
173</div>
174</div>
175</body>
176<?php } else {
177$PAGE = null;
178switch(isset($_GET['page']) ? $_GET['page'] : null)
179{
180	case 'update-result-file-meta':
181		if(VIEWER_CAN_MODIFY_RESULTS && isset($_REQUEST['result_file_id']) && isset($_REQUEST['result_title']) && isset($_REQUEST['result_desc']))
182		{
183			$result_file = new pts_result_file($_REQUEST['result_file_id']);
184			$result_file->set_title($_REQUEST['result_title']);
185			$result_file->set_description($_REQUEST['result_desc']);
186			$result_file->save();
187		}
188		exit;
189	case 'remove-result-object':
190		if(VIEWER_CAN_DELETE_RESULTS && isset($_REQUEST['result_file_id']) && isset($_REQUEST['result_object']))
191		{
192			$result_file = new pts_result_file($_REQUEST['result_file_id']);
193			$result_file->remove_result_object_by_id($_REQUEST['result_object']);
194			$result_file->save();
195		}
196		exit;
197	case 'remove-result-run':
198		if(VIEWER_CAN_DELETE_RESULTS && isset($_REQUEST['result_file_id']) && isset($_REQUEST['result_run']))
199		{
200			$result_file = new pts_result_file($_REQUEST['result_file_id']);
201			$result_file->remove_run($_REQUEST['result_run']);
202			$result_file->save();
203		}
204		exit;
205	case 'rename-result-run':
206		if(VIEWER_CAN_MODIFY_RESULTS && isset($_REQUEST['result_file_id']) && isset($_REQUEST['result_run']) && isset($_REQUEST['new_result_run']))
207		{
208			$result_file = new pts_result_file($_REQUEST['result_file_id']);
209			$result_file->rename_run($_REQUEST['result_run'], $_REQUEST['new_result_run']);
210			$result_file->save();
211		}
212		exit;
213	case 'add-annotation-to-result-object':
214		if(VIEWER_CAN_MODIFY_RESULTS && isset($_REQUEST['result_file_id']) && isset($_REQUEST['result_object']) && isset($_REQUEST['annotation']))
215		{
216			$result_file = new pts_result_file($_REQUEST['result_file_id']);
217			$result_file->update_annotation_for_result_object_by_id($_REQUEST['result_object'], $_REQUEST['annotation']);
218			$result_file->save();
219		}
220		exit;
221	case 'reorder_result_file':
222		if(VIEWER_CAN_MODIFY_RESULTS && isset($_REQUEST['result_file_id']))
223		{
224			$result_file = new pts_result_file($_REQUEST['result_file_id']);
225			if(count($result_file_identifiers = $result_file->get_system_identifiers()) > 1)
226			{
227				if(isset($_POST['reorder_post']))
228				{
229					$sort_array = array();
230
231					foreach($result_file_identifiers as $i => $id)
232					{
233						if(isset($_POST[base64_encode($id)]))
234						{
235							$sort_array[$id] = $_POST[base64_encode($id)];
236						}
237					}
238					asort($sort_array);
239					$sort_array = array_keys($sort_array);
240					$result_file->reorder_runs($sort_array);
241					$result_file->save();
242					echo '<p>Result file is now reordered. <script> window.close(); </script></p>';
243				}
244				else if(isset($_GET['auto_sort']))
245				{
246					sort($result_file_identifiers);
247					$result_file->reorder_runs($result_file_identifiers);
248					$result_file->save();
249					echo '<p>Result file is now auto-sorted. <script> window.close(); </script></p>';
250				}
251				else
252				{
253					echo '<p>Reorder the result file as desired by altering the numbering from lowest to highest or <a href="?page=reorder_result_file&result_file_id=' . $_REQUEST['result_file_id'] . '&auto_sort">auto-sort result file</a>.</p>';
254					echo '<form method="post" action="?page=reorder_result_file&result_file_id=' . $_REQUEST['result_file_id'] . '">';
255					foreach($result_file_identifiers as $i => $id)
256					{
257						echo '<input style="width: 80px;" name="' . base64_encode($id) . '" type="number" min="0" value="' . ($i + 1) . '" />' . $id . '<br />';
258					}
259
260					echo '<input type="hidden" name="reorder_post" value="1" /><input type="submit" value="Reorder Results" /></form>';
261				}
262			}
263
264		/*
265		echo PHP_EOL . 'Enter The New Order To Display The New Results, From Left To Right.' . PHP_EOL;
266
267		$sorted_identifiers = array();
268		do
269		{
270			$extract_identifier = pts_user_io::prompt_text_menu('Select the test run to be showed next', $result_file_identifiers);
271			$sorted_identifiers[] = $extract_identifier;
272
273			$old_identifiers = $result_file_identifiers;
274			$result_file_identifiers = array();
275
276			foreach($old_identifiers as $identifier)
277			{
278				if($identifier != $extract_identifier)
279				{
280					$result_file_identifiers[] = $identifier;
281				}
282			}
283		}
284		while(count($result_file_identifiers) > 0);
285
286		$result_file->reorder_runs($sorted_identifiers);
287		pts_client::save_test_result($result_file->get_file_location(), $result_file->get_xml());
288		pts_client::display_result_view($result_file, false);
289		*/
290
291		}
292		exit;
293	case 'test':
294		$o = new pts_test_profile($_GET['test']);
295		$PAGE .= '<h1>' . $o->get_title() . '</h1>';
296
297		if($o->get_license() == 'Retail' || $o->get_license() == 'Restricted')
298		{
299			$PAGE .= '<p><em>NOTE: This test profile is marked \'' . $o->get_license() . '\' and may have issues running without third-party/commercial dependencies.</em></p>';
300		}
301		if($o->get_status() != 'Verified' && $o->get_status() != null)
302		{
303			$PAGE .= '<p><em>NOTE: This test profile is marked \'' . $o->get_status() . '\' and may have known issues with test installation or execution.</em></p>';
304		}
305
306		$table = array();
307		$table[] = array('Run Identifier: ', $o->get_identifier());
308		$table[] = array('Profile Version: ', $o->get_test_profile_version());
309		$table[] = array('Maintainer: ', $o->get_maintainer());
310		$table[] = array('Test Type: ', $o->get_test_hardware_type());
311		$table[] = array('Software Type: ', $o->get_test_software_type());
312		$table[] = array('License Type: ', $o->get_license());
313		$table[] = array('Test Status: ', $o->get_status());
314		$table[] = array('Supported Platforms: ', implode(', ', $o->get_supported_platforms()));
315		$table[] = array('Project Web-Site: ', '<a target="_blank" href="' . $o->get_project_url() . '">' . $o->get_project_url() . '</a>');
316
317		$download_size = $o->get_download_size();
318		if(!empty($download_size))
319		{
320			$table[] = array('Download Size: ', $download_size . ' MB');
321		}
322
323		$environment_size = $o->get_environment_size();
324		if(!empty($environment_size))
325		{
326			$table[] = array('Environment Size: ', $environment_size . ' MB');
327		}
328
329		$cols = array(array(), array());
330		foreach($table as &$row)
331		{
332			$row[0] = '<strong>' . $row[0] . '</strong>';
333			$cols[0][] = $row[0];
334			$cols[1][] = $row[1];
335		}
336		$PAGE .= '<br /><div style="float: left;">' . implode('<br />', $cols[0]) . '</div>';
337		$PAGE .= '<div style="float: left; padding-left: 15px;">' . implode('<br />', $cols[1]) . '</div>' . '<br style="clear: both;" />';
338		$PAGE .= '<p>'. $o->get_description() . '</p>';
339
340		foreach(array('Pre-Install Message' => $o->get_pre_install_message(), 'Post-Install Message' => $o->get_post_install_message(), 'Pre-Run Message' => $o->get_pre_run_message(), 'Post-Run Message' => $o->get_post_run_message()) as $msg_type => $msg)
341		{
342			if($msg != null)
343			{
344				$PAGE .= '<p><em>' . $msg_type . ': ' . $msg . '</em></p>';
345			}
346		}
347
348		$dependencies = $o->get_external_dependencies();
349		if(!empty($dependencies) && !empty($dependencies[0]))
350		{
351			$PAGE .= PHP_EOL . '<strong>Software Dependencies:</strong>' . '<br />';
352			$PAGE .= implode('<br />', $dependencies);
353		}
354
355		$o_identifier = $o->get_identifier(false);
356		$table = array();
357		$i = 0;
358		$found_result = false;
359		foreach(pts_results::saved_test_results() as $id)
360		{
361			$result_file = new pts_result_file($id);
362			foreach($result_file->get_result_objects() as $result_object)
363			{
364				if($result_object->test_profile->get_identifier(false) == $o_identifier)
365				{
366					if(!$found_result)
367					{
368						$found_result = true;
369						$PAGE .= '<br /><br /><h2>Results Containing This Test</h2><br />';
370					}
371					$PAGE .= '<h2><a href="' . WEB_URL_PATH . 'result/' . $id . '">' . $result_file->get_title() . '</a></h2>';
372					$PAGE .= '<div class="sub"><label for="cr_checkbox_' . $i . '"></label> ' . $result_file->get_test_count() . ' Tests &nbsp; &nbsp; ' . $result_file->get_system_count() . ' Systems &nbsp; &nbsp; ' . date('l j F H:i', strtotime($result_file->get_last_modified())) . ' </div>';
373					$PAGE .= '<div class="desc">' . $result_file->get_description() . '</div>';
374					break;
375					$i++;
376				}
377			}
378		}
379		break;
380	case 'suite':
381		$o = new pts_test_suite($_GET['suite']);
382		$PAGE .= '<h1>' . $o->get_title() . '</h1>';
383
384		$table = array();
385		$table[] = array('Run Identifier: ', $o->get_identifier());
386		$table[] = array('Profile Version: ', $o->get_version());
387		$table[] = array('Maintainer: ', $o->get_maintainer());
388		$table[] = array('Test Type: ', $o->get_suite_type());
389
390		$cols = array(array(), array());
391		foreach($table as &$row)
392		{
393			$row[0] = '<strong>' . $row[0] . '</strong>';
394			$cols[0][] = $row[0];
395			$cols[1][] = $row[1];
396		}
397		$PAGE .= '<br /><div style="float: left;">' . implode('<br />', $cols[0]) . '</div>';
398		$PAGE .= '<div style="float: left; padding-left: 15px;">' . implode('<br />', $cols[1]) . '</div>' . '<br style="clear: both;" />';
399		$PAGE .= '<p>'. $o->get_description() . '</p>';
400		foreach($o->get_contained_test_result_objects() as $ro)
401		{
402			$PAGE .= '<h2><a href="' . WEB_URL_PATH . 'test/' . base64_encode($ro->test_profile->get_identifier()) . '">' . $ro->test_profile->get_title() . '</a></h2>';
403			$PAGE .= '<p>' . $ro->get_arguments_description() . '</p>';
404		}
405		break;
406	case 'tests':
407		$tests = pts_openbenchmarking::available_tests(false, false, true);
408		$tests_to_show = array();
409		foreach($tests as $identifier)
410		{
411			$test_profile = new pts_test_profile($identifier);
412
413			if($test_profile->get_title() == null)
414			{
415				// Don't show unsupported tests
416				continue;
417			}
418
419			$tests_to_show[] = $test_profile;
420		}
421		if(empty($tests_to_show))
422		{
423			$PAGE .= '<p>No cached test profiles found.</p>';
424		}
425		else
426		{
427			$PAGE .= '<p>The ' . count($tests_to_show) . ' test profiles below are cached on the local system and in a current state. For a complete listing of available tests visit <a href="https://openbenchmarking.org/">OpenBenchmarking.org</a>.</p>';
428		}
429
430		$PAGE .= '<div class="pts_test_boxes">';
431		$tests_to_show = array_unique($tests_to_show);
432		function tests_cmp_result_object_sort($a, $b)
433		{
434			$a_comp = $a->get_test_hardware_type() . $a->get_title();
435			$b_comp = $b->get_test_hardware_type() . $b->get_title();
436
437			return strcmp($a_comp, $b_comp);
438		}
439		usort($tests_to_show, 'tests_cmp_result_object_sort');
440		$category = null;
441		$tests_in_category = 0;
442		foreach($tests_to_show as &$test_profile)
443		{
444			if($category != $test_profile->get_test_hardware_type())
445			{
446				$category = $test_profile->get_test_hardware_type();
447				if($category == null) continue;
448				if($tests_in_category > 0)
449				{
450					$PAGE .= '<br style="clear: both;" /><em>' . $tests_in_category . ' Tests</em>';
451				}
452				$tests_in_category = 0;
453				$PAGE .= '</div><a name="' . $category . '"></a>' . PHP_EOL . '<h2>' . $category . '</h2>' . PHP_EOL . '<div class="pts_test_boxes">';
454				$popularity_index = pts_openbenchmarking_client::popular_tests(-1, pts_openbenchmarking_client::read_repository_test_profile_attribute($test_profile, 'test_type'));
455			}
456			if($category == null) continue;
457			$tests_in_category++;
458
459			$last_updated = pts_openbenchmarking_client::read_repository_test_profile_attribute($test_profile, 'last_updated');
460			$versions = pts_openbenchmarking_client::read_repository_test_profile_attribute($test_profile, 'versions');
461			$popularity = isset($popularity_index) && is_array($popularity_index) ? array_search($test_profile->get_identifier(false), $popularity_index) : false;
462			$secondary_message = null;
463
464			if($last_updated > (time() - (60 * 60 * 24 * 30)))
465			{
466				$secondary_message = count($versions) == 1 ? '- <em>Newly Added</em>' : '- <em>Recently Updated</em>';
467			}
468			else if($popularity === 0)
469			{
470				$secondary_message = '- <em>Most Popular</em>';
471			}
472			else if($popularity < 6)
473			{
474				$secondary_message = '- <em>Very Popular</em>';
475			}
476
477			$PAGE .= '<a href="' . WEB_URL_PATH . 'test/' . base64_encode($test_profile->get_identifier()) . '"><div class="table_test_box"><strong>' . $test_profile->get_title(). '</strong><br /><span>~' . pts_strings::plural_handler(max(1, round(pts_openbenchmarking_client::read_repository_test_profile_attribute($test_profile, 'average_run_time') / 60)),
478'min') . ' run-time ' . $secondary_message . '</span></div></a>';
479		}
480		if($tests_in_category > 0)
481		{
482			$PAGE .= '<br style="clear: both;" /><em>' . $tests_in_category . ' Tests</em>';
483		}
484		$PAGE .= '</div>';
485		break;
486	case 'suites':
487		$suites = pts_test_suites::all_suites_cached();
488		$suites_to_show = array();
489		foreach($suites as $identifier)
490		{
491			$test_suite = new pts_test_suite($identifier);
492
493			if($test_suite->get_title() == null)
494			{
495				// Don't show unsupported suites
496				continue;
497			}
498
499			$suites_to_show[] = $test_suite;
500		}
501		if(empty($suites_to_show))
502		{
503			$PAGE .= '<p>No cached test suites found.</p>';
504		}
505		else
506		{
507			$PAGE .= '<p>The ' . count($suites_to_show) . ' test suites below are cached on the local system and in a current state. For a complete listing of available test suites visit <a href="https://openbenchmarking.org/">OpenBenchmarking.org</a>.</p>';
508		}
509
510		$PAGE .= '<div class="pts_test_boxes">';
511		$suites_to_show = array_unique($suites_to_show);
512		function suites_cmp_result_object_sort($a, $b)
513		{
514			$a_comp = $a->get_suite_type() . $a->get_title();
515			$b_comp = $b->get_suite_type() . $b->get_title();
516
517			return strcmp($a_comp, $b_comp);
518		}
519		usort($suites_to_show, 'suites_cmp_result_object_sort');
520		$category = null;
521		$suites_in_category = 0;
522		foreach($suites_to_show as &$test_suite)
523		{
524			if($category != $test_suite->get_suite_type())
525			{
526				$category = $test_suite->get_suite_type();
527				if($category == null) continue;
528				if($suites_in_category > 0)
529				{
530					$PAGE .= '<br style="clear: both;" /><em>' . $suites_in_category . ' Suites</em>';
531				}
532				$suites_in_category = 0;
533				$PAGE .= '</div><a name="' . $category . '"></a>' . PHP_EOL . '<h2>' . $category . '</h2>' . PHP_EOL . '<div class="pts_test_boxes">';
534			}
535			if($category == null) continue;
536			$suites_in_category++;
537
538			$last_updated = pts_openbenchmarking_client::read_repository_test_suite_attribute($test_suite->get_identifier(), 'last_updated');
539			$versions = pts_openbenchmarking_client::read_repository_test_suite_attribute($test_suite->get_identifier(), 'versions');
540			$secondary_message = null;
541
542			if($last_updated > (time() - (60 * 60 * 24 * 45)))
543			{
544				// Mark it as newly updated if uploaded in past 3 weeks
545				$secondary_message = count($versions) == 1 ? '- <em>Newly Added</em>' : '- <em>Recently Updated</em>';
546			}
547
548			$PAGE .= '<a href="' . WEB_URL_PATH . 'suite/' . base64_encode($test_suite->get_identifier()) . '"><div class="table_test_box"><strong>' . $test_suite->get_title(). '</strong><br /><span>' . $test_suite->get_test_count() . ' Tests (' . $test_suite->get_unique_test_count() . ' Unique Profiles) ' . $secondary_message . '</span></div></a>';
549		}
550		if($suites_in_category > 0)
551		{
552			$PAGE .= '<br style="clear: both;" /><em>' . $suites_in_category . ' Tests</em>';
553		}
554		$PAGE .= '</div>';
555		break;
556	case 'result':
557		if(isset($_POST) && !empty($_POST) && !isset($_POST['log_select']))
558		{
559			$result_link = null;
560			foreach(array_keys($_POST) as $key)
561			{
562				if($_REQUEST[$key] != null && $_REQUEST[$key] != '0' && $key != 'submit')
563				{
564					if(is_array($_REQUEST[$key]))
565					{
566						$_REQUEST[$key] = implode(',', $_REQUEST[$key]);
567					}
568					$result_link .= '&' . $key . '=' . urlencode(str_replace('.', '_DD_', $_REQUEST[$key]));
569				}
570			}
571			$server_uri = $_SERVER['REQUEST_URI'];
572			if(($x = strpos($server_uri, '&')) !== false)
573			{
574				$server_uri = substr($server_uri, 0, $x);
575			}
576
577			header('Location: ' . $server_uri . $result_link);
578		}
579		$result_file = null;
580		$possible_results = explode(',', $_GET['result']);
581		$results_viewing = array();
582		foreach($possible_results as $rid)
583		{
584			if(pts_results::is_saved_result_file($rid))
585			{
586				if($result_file == null)
587				{
588					$result_file = new pts_result_file($rid);
589					$results_viewing[] = $rid;
590					/*if(count($possible_results) > 1)
591					{
592						$result_file->rename_run('PREFIX', $result_file->get_title());
593					}*/
594				}
595				else
596				{
597					$rf = new pts_result_file($rid);
598					$result_file->merge(array(new pts_result_merge_select($rf)), 0, $rf->get_title(), true, true);
599				}
600			}
601		}
602		if($result_file == null)
603		{
604			break;
605		}
606		define('TITLE', $result_file->get_title() . ' - Phoronix Test Suite');
607		$embed = new pts_result_viewer_embed($result_file, $results_viewing[0]);
608		$embed->allow_modifying_results(VIEWER_CAN_MODIFY_RESULTS && count($results_viewing) == 1);
609		$embed->allow_deleting_results(VIEWER_CAN_DELETE_RESULTS && count($results_viewing) == 1);
610		$PAGE = $embed->get_html();
611		break;
612	case 'index':
613	default:
614		if(isset($uri_segments[0]) && is_file($uri_segments[0] . '.html'))
615		{
616			define('TITLE', 'Phoronix Test Suite ' . PTS_VERSION);
617			$PAGE = file_get_contents($uri_segments[0] . '.html');
618		}
619		else
620		{
621			define('TITLE', 'Phoronix Test Suite ' . PTS_VERSION . ' Result Portal');
622			$PAGE .= '<form name="search_results" id="search_results" action="' . CURRENT_URI . '" method="post"><input type="text" name="search" id="u_search" placeholder="Search Test Results" value="' . (isset($_POST['search']) ? $_POST['search'] : null) . '" /> <select name="sort_results_by"><option value="date">Sort By Date</option><option value="title">Sort By Title</option><option value="test_count">Sort By Test Count</option><option value="system_count">Sort By System Count</option></select> <input class="primary-button" type="submit" value="Update" />
623	</form>';
624			$leading_msg = null;
625			if(VIEWER_CAN_DELETE_RESULTS && isset($_GET['remove_result']) && $_GET['remove_result'] && pts_results::is_saved_result_file($_GET['remove_result']))
626			{
627				$deleted = pts_results::remove_saved_result_file($_GET['remove_result']);
628				if($deleted)
629				{
630					$leading_msg = 'Deleted the <em>' . $_GET['remove_result'] . '</em> result file.';
631				}
632			}
633
634			$results = pts_results::query_saved_result_files((isset($_POST['search']) ? $_POST['search'] : null), (isset($_REQUEST['sort_results_by']) ? $_REQUEST['sort_results_by'] : null));
635
636			$total_result_points = 0;
637			foreach($results as $id => $result_file)
638			{
639				$total_result_points += $result_file->get_test_count();
640			}
641
642			$PAGE .= '<div class="sub" style="margin: 6px 0 30px">' . ($result_file_count = count($results)) . ' Result Files Containing A Combined ' . $total_result_points . ' Test Results</div>';
643			$PAGE .= '<form name="compare_results" id="compare_results_id" action="' . CURRENT_URI . '" method="post"><input type="submit" value="Compare Results" id="compare_results_submit" />';
644			$i = 0;
645			foreach($results as $id => $result_file)
646			{
647				$i++;
648				$PAGE .= '<h2><a href="' . WEB_URL_PATH . 'result/' . $id . '">' . $result_file->get_title() . '</a></h2>';
649				$PAGE .= '<div class="sub"><input type="checkbox" name="checkbox_compare_results[]" value="' . $id . '" id="cr_checkbox_' . $i . '" /> <label for="cr_checkbox_' . $i . '"><span onclick="javascript:document.getElementById(\'compare_results_id\').submit(); return false;">Compare Results</span></label> ' . $result_file->get_test_count() . ' Tests &nbsp; &nbsp; ' . $result_file->get_system_count() . ' Systems &nbsp; &nbsp; ' . date('l j F H:i', strtotime($result_file->get_last_modified())) . ' ' . (VIEWER_CAN_DELETE_RESULTS ? ' &nbsp; &nbsp; <span onclick="javascript:delete_result_file(\'' . $id . '\'); return false;">DELETE RESULT FILE</span>' : null) . '</div>';
650				$PAGE .= '<div class="desc">' . $result_file->get_description() . '</div>';
651
652				// Avoid showing geo mean for every result file due to too computationally intensive
653				$geometric_mean = $result_file_count > 40 ? false : pts_result_file_analyzer::generate_geometric_mean_result($result_file);
654				if($geometric_mean)
655				{
656					$geo_display = null;
657					$geo_display_count = 0;
658					$best_result = $geometric_mean->test_result_buffer->get_max_value(false);
659					foreach($geometric_mean->test_result_buffer as &$buffers)
660					{
661						if(empty($buffers))
662							continue;
663
664						$max_value = 0;
665						foreach($buffers as &$buffer_item)
666						{
667							$v = $buffer_item->get_result_value();
668							if(!is_numeric($v)) continue;
669							$percentage = ($v / $best_result) * 100;
670							$bg = pts_render::identifier_to_brand_color($buffer_item->get_result_identifier(), '');
671							if($bg)
672							{
673								$bg = 'background: ' . $bg . '; color: #FFF';
674							}
675							$geo_display .=  '<div class="geo_bg_graph" style="margin-right: ' . round(100 - $percentage, 1) . '%; ' . $bg . '"><strong>' . $buffer_item->get_result_identifier() . ':</strong> ' . $v . ' (' . round($percentage, 2) . '%)</div>';
676							$geo_display_count++;
677						}
678					}
679					if($geo_display_count > 1)
680					{
681						$PAGE .= '<span class="sub_header">Geometric Mean</span>' . $geo_display;
682					}
683				}
684				$PAGE .= '<br />';
685			}
686			$PAGE .= '</form>';
687		}
688		break;
689
690}
691
692//define('PAGE', $PAGE);
693
694?>
695<!doctype html>
696<html lang="en">
697<head>
698  <title><?php echo defined('TITLE') ? TITLE : ''; ?></title>
699<link rel="stylesheet" href="<?php echo CSS_RESULT_VIEWER_PATH; ?>">
700<link rel="icon" type="image/png" href="<?php echo WEB_URL_PATH; ?>favicon.png">
701<script type="text/javascript" src="<?php echo WEB_URL_PATH; ?>result-viewer.js?<?php echo PTS_CORE_VERSION; ?>"></script>
702<script>
703var WEB_URL_PATH = "<?php echo WEB_URL_PATH; ?>";
704</script>
705<link href="//fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
706</head>
707<body>
708<div id="header">
709<div style="float: left; margin-top: 2px;">
710<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewbox="0 0 76 41" width="76" height="41" preserveAspectRatio="xMinYMin meet">
711  <path d="m74 22v9m-5-16v16m-5-28v28m-23-2h12.5c2.485281 0 4.5-2.014719 4.5-4.5s-2.014719-4.5-4.5-4.5h-8c-2.485281 0-4.5-2.014719-4.5-4.5s2.014719-4.5 4.5-4.5h12.5m-21 5h-11m11 13h-2c-4.970563 0-9-4.029437-9-9v-20m-24 40v-20c0-4.970563 4.0294373-9 9-9 4.970563 0 9 4.029437 9 9s-4.029437 9-9 9h-9" stroke="#696969" stroke-width="4" fill="none" />
712</svg></div> <div style="float: left; margin: 5px 0 0 10px;"> <a href="<?php echo WEB_URL_PATH; ?>">Result Viewer</a></div>
713<ul>
714<?php if(PTS_OPENBENCHMARKING_SCRATCH_PATH != null) { ?>
715<li><a href="<?php echo WEB_URL_PATH; ?>tests/">Test Profiles</a></li>
716<li><a href="<?php echo WEB_URL_PATH; ?>suites/">Test Suites</a></li>
717<?php } ?>
718<li><a href="<?php echo WEB_URL_PATH; ?>">Results</a></li>
719</ul>
720</div>
721
722<?php
723
724if((!isset($leading_msg) || empty($leading_msg)) && defined('PTS_CORE_STORAGE') && ($motd = pts_storage_object::read_from_file(PTS_CORE_STORAGE, 'MOTD_HTML')) != null)
725{
726	$leading_msg = '<em>' . $motd . '</em>';
727}
728
729if(isset($leading_msg) && $leading_msg) { echo '<div id="leading_message">' . $leading_msg . '</div>'; } ?>
730<div id="main_area">
731<?php echo $PAGE; ?>
732</div>
733<div id="footer"><hr /><br /><a href="https://www.phoronix-test-suite.com/">Phoronix Test Suite</a> <?php echo PTS_VERSION; ?> - Generated <?php echo date('j F Y H:i:s'); ?></div>
734</body>
735<?php }
736if(function_exists('session_start'))
737{
738	session_write_close();
739}
740?>
741</html>
742