From 3af87733bef1447c8d5c3235a57f666692a122b3 Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Wed, 25 Feb 2026 09:54:52 +0100 Subject: [PATCH] [ITU Award] Speed increase --- application/controllers/Awards.php | 97 +++---- application/models/Itu.php | 380 +++++++++++++++---------- application/views/awards/itu/index.php | 265 ++++++++++------- assets/js/sections/itumap.js | 3 +- 4 files changed, 446 insertions(+), 299 deletions(-) diff --git a/application/controllers/Awards.php b/application/controllers/Awards.php index 6ccffc138..2e6e881ec 100644 --- a/application/controllers/Awards.php +++ b/application/controllers/Awards.php @@ -1978,9 +1978,9 @@ class Awards extends CI_Controller { $this->load->model('itu'); $this->load->model('modes'); $this->load->model('bands'); - $data['user_map_custom'] = $this->optionslib->get_map_custom(); $data['worked_bands'] = $this->bands->get_worked_bands('cq'); + $data['user_map_custom'] = $this->optionslib->get_map_custom(); $data['modes'] = $this->modes->active(); // Used in the view for mode select if ($this->input->post('band') != NULL) { // Band is not set when page first loads. @@ -1997,35 +1997,43 @@ class Awards extends CI_Controller { $data['bands'] = $bands; // Used for displaying selected band(s) in the table in the view - if($this->input->method() === 'post') { - $postdata['qsl'] = $this->security->xss_clean($this->input->post('qsl')); - $postdata['lotw'] = $this->security->xss_clean($this->input->post('lotw')); - $postdata['eqsl'] = $this->security->xss_clean($this->input->post('eqsl')); - $postdata['qrz'] = $this->security->xss_clean($this->input->post('qrz')); - $postdata['clublog'] = $this->security->xss_clean($this->input->post('clublog')); - $postdata['worked'] = $this->security->xss_clean($this->input->post('worked')); - $postdata['confirmed'] = $this->security->xss_clean($this->input->post('confirmed')); - $postdata['notworked'] = $this->security->xss_clean($this->input->post('notworked')); - $postdata['band'] = $this->security->xss_clean($this->input->post('band')); - $postdata['mode'] = $this->security->xss_clean($this->input->post('mode')); - } - else { // Setting default values at first load of page - $postdata['qsl'] = 1; - $postdata['lotw'] = 1; - $postdata['eqsl'] = 0; - $postdata['qrz'] = 0; - $postdata['clublog'] = 0; - $postdata['worked'] = 1; - $postdata['confirmed'] = 1; - $postdata['notworked'] = 1; - $postdata['band'] = 'All'; + if($this->input->method() === 'post') { + $postdata['qsl'] = ($this->input->post('qsl',true) ?? 0) == 0 ? NULL: 1; + $postdata['lotw'] = ($this->input->post('lotw',true) ?? 0) == 0 ? NULL: 1; + $postdata['eqsl'] = ($this->input->post('eqsl',true) ?? 0) == 0 ? NULL: 1; + $postdata['qrz'] = ($this->input->post('qrz',true) ?? 0) == 0 ? NULL: 1; + $postdata['clublog'] = ($this->input->post('clublog',true) ?? 0) == 0 ? NULL: 1; + $postdata['worked'] = ($this->input->post('worked',true) ?? 0) == 0 ? NULL: 1; + $postdata['confirmed'] = ($this->input->post('confirmed',true) ?? 0) == 0 ? NULL: 1; + $postdata['notworked'] = ($this->input->post('notworked',true) ?? 0) == 0 ? NULL: 1; + $postdata['band'] = $this->security->xss_clean($this->input->post('band')); + $postdata['mode'] = $this->security->xss_clean($this->input->post('mode')); + $postdata['datefrom'] = $this->security->xss_clean($this->input->post('dateFrom')); + $postdata['dateto'] = $this->security->xss_clean($this->input->post('dateTo')); + } + else { // Setting default values at first load of page + $postdata['qsl'] = 1; + $postdata['lotw'] = 1; + $postdata['eqsl'] = NULL; + $postdata['qrz'] = NULL; + $postdata['clublog'] = NULL; + $postdata['worked'] = 1; + $postdata['confirmed'] = 1; + $postdata['notworked'] = 1; + $postdata['band'] = 'All'; $postdata['mode'] = 'All'; - } + $postdata['datefrom'] = null; + $postdata['dateto'] = null; + } + + $data['posted_band'] = $postdata['band']; if ($logbooks_locations_array) { $location_list = "'".implode("','",$logbooks_locations_array)."'"; - $data['itu_array'] = $this->itu->get_itu_array($bands, $postdata, $location_list); - $data['itu_summary'] = $this->itu->get_itu_summary($bands, $postdata, $location_list); + $itu_result = $this->itu->get_itu_array($bands, $postdata, $location_list); + // Extract bands data and summary from the result + $data['itu_array'] = ($itu_result && isset($itu_result['bands'])) ? $itu_result['bands'] : null; + $data['itu_summary'] = ($itu_result && isset($itu_result['summary'])) ? $itu_result['summary'] : null; } else { $location_list = null; $data['itu_array'] = null; @@ -2048,8 +2056,16 @@ class Awards extends CI_Controller { $logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook')); $this->load->model('itu'); + $this->load->model('bands'); - $bands[] = $this->input->post('band'); + $data['worked_bands'] = $this->bands->get_worked_bands('cq'); + + if ($this->input->post('band') == 'All') { + $bands = $data['worked_bands']; + } + else { + $bands[] = $this->input->post('band'); + } $postdata['qsl'] = $this->input->post('qsl') == 0 ? NULL: 1; $postdata['lotw'] = $this->input->post('lotw') == 0 ? NULL: 1; @@ -2061,34 +2077,15 @@ class Awards extends CI_Controller { $postdata['notworked'] = $this->input->post('notworked') == 0 ? NULL: 1; $postdata['band'] = $this->security->xss_clean($this->input->post('band')); $postdata['mode'] = $this->security->xss_clean($this->input->post('mode')); + $postdata['datefrom'] = $this->security->xss_clean($this->input->post('dateFrom')); + $postdata['dateto'] = $this->security->xss_clean($this->input->post('dateTo')); if ($logbooks_locations_array) { $location_list = "'".implode("','",$logbooks_locations_array)."'"; - $itu_array = $this->itu->get_itu_array($bands, $postdata, $location_list); + $zones = $this->itu->get_itu_array($bands, $postdata, $location_list, true); } else { $location_list = null; - $itu_array = null; - } - - $zones = array(); - - foreach ($itu_array as $itu => $value) { - foreach ($value as $key) { - if($key != "") { - if (strpos($key, '>W<') !== false) { - $zones[] = 'W'; - break; - } - if (strpos($key, '>C<') !== false) { - $zones[] = 'C'; - break; - } - if (strpos($key, '-') !== false) { - $zones[] = '-'; - break; - } - } - } + $zones = array(); } header('Content-Type: application/json'); diff --git a/application/models/Itu.php b/application/models/Itu.php index 96ace6daa..ddc623000 100644 --- a/application/models/Itu.php +++ b/application/models/Itu.php @@ -1,12 +1,12 @@ load->library('Genfunctions'); } - function get_itu_array($bands, $postdata, $location_list) { + function get_itu_array($bands, $postdata, $location_list, $map = false) { $ituZ = array(); // Used for keeping track of which states that are not worked for ($i = 1; $i <= 90; $i++) { @@ -15,65 +15,224 @@ class Itu extends CI_Model{ $qsl = $this->genfunctions->gen_qsl_from_postdata($postdata); + // Initialize all bands to dash foreach ($bands as $band) { for ($i = 1; $i <= 90; $i++) { - $banditu[$i][$band] = '-'; // Sets all to dash to indicate no result + $bandItu[$i][$band] = '-'; // Sets all to dash to indicate no result + } + } + + // Initialize summary counters only for the bands passed in + foreach ($bands as $band) { + $summary['worked'][$band] = 0; + $summary['confirmed'][$band] = 0; + } + $summary['worked']['Total'] = 0; + $summary['confirmed']['Total'] = 0; + + // Track unique zone/band combinations for totals + $workedZones = []; // [band][zone] = true + $confirmedZones = []; // [band][zone] = true + + // Create a lookup array for valid bands + $validBands = array_flip($bands); // ['160m' => true, '80m' => true, etc] + + $itudata = $this->getItuZoneData($location_list, $postdata); + $itudata_sat = $this->getItuZoneDataSat($location_list, $postdata); + + foreach ($itudata as $itu) { + // Skip if this band is not in our requested bands list + if (!isset($validBands[$itu->col_band])) { + continue; } - if ($postdata['worked'] != NULL) { - $ituBand = $this->getituWorked($location_list, $band, $postdata); - foreach ($ituBand as $line) { - $banditu[$line->col_ituz][$band] = '
col_ituz) . '","' . $band . '","All", "All","'. $postdata['mode'] . '","ITU","")\'>W
'; - $ituZ[$line->col_ituz]['count']++; + $ituZ[$itu->col_ituz]['count']++; // Count each itu zone + + // Check if confirmed based on the confirmation types selected in postdata + $isConfirmed = false; + $confirmationLetters = ''; + if (isset($postdata['qsl']) && $postdata['qsl'] == 1 && $itu->qsl == 1) { + $isConfirmed = true; + $confirmationLetters .= 'Q'; + } + if (isset($postdata['lotw']) && $postdata['lotw'] == 1 && $itu->lotw == 1) { + $isConfirmed = true; + $confirmationLetters .= 'L'; + } + if (isset($postdata['eqsl']) && $postdata['eqsl'] == 1 && $itu->eqsl == 1) { + $isConfirmed = true; + $confirmationLetters .= 'E'; + } + if (isset($postdata['qrz']) && $postdata['qrz'] == 1 && $itu->qrz == 1) { + $isConfirmed = true; + $confirmationLetters .= 'Z'; + } + if (isset($postdata['clublog']) && $postdata['clublog'] == 1 && $itu->clublog == 1) { + $isConfirmed = true; + $confirmationLetters .= 'C'; + } + + if ($isConfirmed) { + $bandItu[$itu->col_ituz][$itu->col_band] = '
col_ituz) . '","' . $itu->col_band . '","All", "All","'. $postdata['mode'] . '","ITUZone","'.$qsl.'")\'>' . $confirmationLetters . '
'; + // Track confirmed zones for summary + if (!isset($confirmedZones[$itu->col_band][$itu->col_ituz])) { + $confirmedZones[$itu->col_band][$itu->col_ituz] = true; + $summary['confirmed'][$itu->col_band]++; + } + } else { + $bandItu[$itu->col_ituz][$itu->col_band] = '
col_ituz) . '","' . $itu->col_band . '","All", "All","'. $postdata['mode'] . '","ITUZone","")\'>W
'; + } + + // Track worked zones for summary + if (!isset($workedZones[$itu->col_band][$itu->col_ituz])) { + $workedZones[$itu->col_band][$itu->col_ituz] = true; + $summary['worked'][$itu->col_band]++; + } + } + + foreach ($itudata_sat as $itu) { + // Skip if this band is not in our requested bands list + if (!isset($validBands[$itu->col_band])) { + continue; + } + + $ituZ[$itu->col_ituz]['count']++; // Count each itu zone + + // Check if confirmed based on the confirmation types selected in postdata + $isConfirmed = false; + $confirmationLetters = ''; + if (isset($postdata['qsl']) && $postdata['qsl'] == 1 && $itu->qsl == 1) { + $isConfirmed = true; + $confirmationLetters .= 'Q'; + } + if (isset($postdata['lotw']) && $postdata['lotw'] == 1 && $itu->lotw == 1) { + $isConfirmed = true; + $confirmationLetters .= 'L'; + } + if (isset($postdata['eqsl']) && $postdata['eqsl'] == 1 && $itu->eqsl == 1) { + $isConfirmed = true; + $confirmationLetters .= 'E'; + } + if (isset($postdata['qrz']) && $postdata['qrz'] == 1 && $itu->qrz == 1) { + $isConfirmed = true; + $confirmationLetters .= 'Z'; + } + if (isset($postdata['clublog']) && $postdata['clublog'] == 1 && $itu->clublog == 1) { + $isConfirmed = true; + $confirmationLetters .= 'C'; + } + + if ($isConfirmed) { + $bandItu[$itu->col_ituz][$itu->col_band] = '
col_ituz) . '","' . $itu->col_band . '","All", "All","'. $postdata['mode'] . '","ITUZone","'.$qsl.'")\'>' . $confirmationLetters . '
'; + // Track confirmed zones for summary + if (!isset($confirmedZones[$itu->col_band][$itu->col_ituz])) { + $confirmedZones[$itu->col_band][$itu->col_ituz] = true; + $summary['confirmed'][$itu->col_band]++; + } + } else { + $bandItu[$itu->col_ituz][$itu->col_band] = '
col_ituz) . '","' . $itu->col_band . '","All", "All","'. $postdata['mode'] . '","ITUZone","")\'>W
'; + } + + // Track worked zones for summary + if (!isset($workedZones[$itu->col_band][$itu->col_ituz])) { + $workedZones[$itu->col_band][$itu->col_ituz] = true; + $summary['worked'][$itu->col_band]++; + } + } + + // Calculate totals across all bands (excluding SAT) + $totalWorkedZones = []; + $totalConfirmedZones = []; + foreach ($workedZones as $band => $zones) { + // Skip SAT for totals + if ($band === 'SAT') { + continue; + } + foreach ($zones as $zone => $true) { + if (!isset($totalWorkedZones[$zone])) { + $totalWorkedZones[$zone] = true; + $summary['worked']['Total']++; } } - if ($postdata['confirmed'] != NULL) { - $ituBand = $this->getituConfirmed($location_list, $band, $postdata); - foreach ($ituBand as $line) { - $banditu[$line->col_ituz][$band] = '
col_ituz) . '","' . $band . '","All", "All","'. $postdata['mode'] . '","ITU","'.$qsl.'")\'>C
'; - $ituZ[$line->col_ituz]['count']++; + } + foreach ($confirmedZones as $band => $zones) { + // Skip SAT for totals + if ($band === 'SAT') { + continue; + } + foreach ($zones as $zone => $true) { + if (!isset($totalConfirmedZones[$zone])) { + $totalConfirmedZones[$zone] = true; + $summary['confirmed']['Total']++; } } } - // We want to remove the worked zones in the list, since we do not want to display them - if ($postdata['worked'] == NULL) { - $ituBand = $this->getituWorked($location_list, $postdata['band'], $postdata); - foreach ($ituBand as $line) { - unset($banditu[$line->col_ituz]); + // Remove zones based on postdata filters + for ($i = 1; $i <= 90; $i++) { + // Remove not-worked zones if filter is disabled + if ($postdata['notworked'] == NULL && $ituZ[$i]['count'] == 0) { + unset($bandItu[$i]); + continue; + } + + // Remove worked-only zones if filter is disabled + if ($postdata['worked'] == NULL && $ituZ[$i]['count'] > 0 && !isset($totalConfirmedZones[$i])) { + unset($bandItu[$i]); + continue; + } + + // Remove confirmed zones if filter is disabled + if ($postdata['confirmed'] == NULL && isset($totalConfirmedZones[$i])) { + unset($bandItu[$i]); + continue; } } - // We want to remove the confirmed zones in the list, since we do not want to display them - if ($postdata['confirmed'] == NULL) { - $ituBand = $this->getituConfirmed($location_list, $postdata['band'], $postdata); - foreach ($ituBand as $line) { - unset($banditu[$line->col_ituz]); + // If this is for the map, return simplified format + if ($map) { + $mapZones = []; + if ($bands[0] == 'SAT') { + for ($i = 1; $i <= 90; $i++) { + if ($ituZ[$i]['count'] == 0) { + $mapZones[$i-1] = '-'; // Not worked + } elseif (isset($confirmedZones['SAT'][$i])) { + $mapZones[$i-1] = 'C'; // Confirmed + } else { + $mapZones[$i-1] = 'W'; // Worked but not confirmed + } + } + } else { + for ($i = 1; $i <= 90; $i++) { + if (isset($totalConfirmedZones[$i])) { + $mapZones[$i-1] = 'C'; // Confirmed + } else if (isset($totalWorkedZones[$i])) { + $mapZones[$i-1] = 'W'; // Worked but not confirmed + } else { + $mapZones[$i-1] = '-'; // Not worked + } + } } + return $mapZones; } - if ($postdata['notworked'] == NULL) { - for ($i = 1; $i <= 90; $i++) { - if ($ituZ[$i]['count'] == 0) { - unset($banditu[$i]); - }; - } - } - - if (isset($banditu)) { - return $banditu; + if (isset($bandItu)) { + // Return both the band data and summary + return ['bands' => $bandItu, 'summary' => $summary]; } else { return 0; } } - /* - * Function returns all worked, but not confirmed states - * $postdata contains data from the form, in this case Lotw or QSL are used - */ - function getituWorked($location_list, $band, $postdata) { + function getItuZoneData($location_list, $postdata) { $bindings=[]; - $sql = "SELECT distinct col_ituz FROM " . $this->config->item('table_name') . " thcv + $sql = "SELECT thcv.col_ituz, thcv.col_band, + MAX(case when thcv.col_lotw_qsl_rcvd ='Y' then 1 else 0 end) as lotw, + MAX(case when thcv.col_qsl_rcvd = 'Y' then 1 else 0 end) as qsl, + MAX(case when thcv.col_eqsl_qsl_rcvd = 'Y' then 1 else 0 end) as eqsl, + MAX(case when thcv.COL_QRZCOM_QSO_DOWNLOAD_STATUS= 'Y' then 1 else 0 end) as qrz, + MAX(case when thcv.COL_CLUBLOG_QSO_DOWNLOAD_STATUS = 'Y' then 1 else 0 end) as clublog + FROM " . $this->config->item('table_name') . " thcv where station_id in (" . $location_list . ") and col_ituz <= 90 and col_ituz <> ''"; if ($postdata['mode'] != 'All') { @@ -82,36 +241,34 @@ class Itu extends CI_Model{ $bindings[]=$postdata['mode']; } - $sql .= $this->genfunctions->addBandToQuery($band,$bindings); - - $sql .= " and not exists (select 1 from " . $this->config->item('table_name') . - " where station_id in (" . $location_list . - ") and col_ituz = thcv.col_ituz and col_ituz <> '' "; - - if ($postdata['mode'] != 'All') { - $sql .= " and (col_mode = ? or col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; + if ($postdata['datefrom'] != NULL) { + $sql .= " and col_time_on >= ?"; + $bindings[]=$postdata['datefrom'] . ' 00:00:00'; } - $sql .= $this->genfunctions->addBandToQuery($band,$bindings); + if ($postdata['dateto'] != NULL) { + $sql .= " and col_time_on <= ?"; + $bindings[]=$postdata['dateto'] . ' 23:59:59'; + } - $sql .= $this->genfunctions->addQslToQuery($postdata); + $sql .= " and col_prop_mode != 'SAT'"; - $sql .= ")"; + $sql .= " GROUP BY thcv.col_ituz, thcv.col_band"; $query = $this->db->query($sql,$bindings); return $query->result(); } - /* - * Function returns all confirmed states on given band and on LoTW or QSL - * $postdata contains data from the form, in this case Lotw or QSL are used - */ - function getituConfirmed($location_list, $band, $postdata) { + function getItuZoneDataSat($location_list, $postdata) { $bindings=[]; - $sql = "SELECT distinct col_ituz FROM " . $this->config->item('table_name') . " thcv + $sql = "SELECT thcv.col_ituz, 'SAT' as col_band, + MAX(case when thcv.col_lotw_qsl_rcvd ='Y' then 1 else 0 end) as lotw, + MAX(case when thcv.col_qsl_rcvd = 'Y' then 1 else 0 end) as qsl, + MAX(case when thcv.col_eqsl_qsl_rcvd = 'Y' then 1 else 0 end) as eqsl, + MAX(case when thcv.COL_QRZCOM_QSO_DOWNLOAD_STATUS= 'Y' then 1 else 0 end) as qrz, + MAX(case when thcv.COL_CLUBLOG_QSO_DOWNLOAD_STATUS = 'Y' then 1 else 0 end) as clublog + FROM " . $this->config->item('table_name') . " thcv where station_id in (" . $location_list . ") and col_ituz <= 90 and col_ituz <> ''"; if ($postdata['mode'] != 'All') { @@ -120,106 +277,23 @@ class Itu extends CI_Model{ $bindings[]=$postdata['mode']; } - $sql .= $this->genfunctions->addBandToQuery($band,$bindings); + if ($postdata['datefrom'] != NULL) { + $sql .= " and col_time_on >= ?"; + $bindings[]=$postdata['datefrom'] . ' 00:00:00'; + } - $sql .= $this->genfunctions->addQslToQuery($postdata); + if ($postdata['dateto'] != NULL) { + $sql .= " and col_time_on <= ?"; + $bindings[]=$postdata['dateto'] . ' 23:59:59'; + } + + $sql .= " and col_prop_mode = 'SAT'"; + + $sql .= " GROUP BY thcv.col_ituz"; $query = $this->db->query($sql,$bindings); return $query->result(); } - - /* - * Function gets worked and confirmed summary on each band on the active stationprofile - */ - function get_itu_summary($bands, $postdata, $location_list) { - foreach ($bands as $band) { - $worked = $this->getSummaryByBand($band, $postdata, $location_list); - $confirmed = $this->getSummaryByBandConfirmed($band, $postdata, $location_list); - $ituSummary['worked'][$band] = $worked[0]->count; - $ituSummary['confirmed'][$band] = $confirmed[0]->count; - } - - $workedTotal = $this->getSummaryByBand($postdata['band'], $postdata, $location_list); - $confirmedTotal = $this->getSummaryByBandConfirmed($postdata['band'], $postdata, $location_list); - - $ituSummary['worked']['Total'] = $workedTotal[0]->count; - $ituSummary['confirmed']['Total'] = $confirmedTotal[0]->count; - - return $ituSummary; - } - - function getSummaryByBand($band, $postdata, $location_list) { - $bindings=[]; - $sql = "SELECT count(distinct thcv.col_ituz) as count FROM " . $this->config->item('table_name') . " thcv"; - - $sql .= " where station_id in (" . $location_list . ') and col_ituz <= 90 and col_ituz > 0'; - - if ($band == 'SAT') { - $sql .= " and thcv.col_prop_mode = ?"; - $bindings[]=$band; - } else if ($band == 'All') { - $this->load->model('bands'); - - $bandslots = $this->bands->get_worked_bands('cq'); - - $bandslots_list = "'".implode("','",$bandslots)."'"; - - $sql .= " and thcv.col_band in (" . $bandslots_list . ")" . - " and thcv.col_prop_mode !='SAT'"; - } else { - $sql .= " and thcv.col_prop_mode !='SAT'"; - $sql .= " and thcv.col_band = ?"; - $bindings[]=$band; - } - - if ($postdata['mode'] != 'All') { - $sql .= " and (col_mode = ? or col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - $query = $this->db->query($sql,$bindings); - - return $query->result(); - } - - function getSummaryByBandConfirmed($band, $postdata, $location_list){ - $bindings=[]; - $sql = "SELECT count(distinct thcv.col_ituz) as count FROM " . $this->config->item('table_name') . " thcv"; - - $sql .= " where station_id in (" . $location_list . ') and col_ituz <= 90 and col_ituz > 0'; - - if ($band == 'SAT') { - $sql .= " and thcv.col_prop_mode = ?"; - $bindings[]=$band; - } else if ($band == 'All') { - $this->load->model('bands'); - - $bandslots = $this->bands->get_worked_bands('cq'); - - $bandslots_list = "'".implode("','",$bandslots)."'"; - - $sql .= " and thcv.col_band in (" . $bandslots_list . ")" . - " and thcv.col_prop_mode !='SAT'"; - } else { - $sql .= " and thcv.col_prop_mode !='SAT'"; - $sql .= " and thcv.col_band = ?"; - $bindings[]=$band; - } - - if ($postdata['mode'] != 'All') { - $sql .= " and (col_mode = ? or col_submode = ?)"; - $bindings[]=$postdata['mode']; - $bindings[]=$postdata['mode']; - } - - $sql .= $this->genfunctions->addQslToQuery($postdata); - - $query = $this->db->query($sql, $bindings); - - return $query->result(); - } - } diff --git a/application/views/awards/itu/index.php b/application/views/awards/itu/index.php index c56a4e4f1..e5aae5fd9 100644 --- a/application/views/awards/itu/index.php +++ b/application/views/awards/itu/index.php @@ -31,96 +31,130 @@
-
+
+
+