Ensure that all board config variables are available on all config screens #2433

This commit is contained in:
Kijin Sung 2025-06-01 17:32:07 +09:00
parent 967f67ec99
commit 936e1931c0
6 changed files with 166 additions and 39 deletions

View file

@ -142,6 +142,9 @@ class BoardAdminView extends Board {
return $this->alertMessage('msg_invalid_request');
}
// Fix missing module configuration values
BoardModel::fixModuleConfig($this->module_info);
// get the skins list
$oModuleModel = getModel('module');
$skin_list = $oModuleModel->getSkins($this->module_path);
@ -199,6 +202,10 @@ class BoardAdminView extends Board {
* additonal setup panel is for connecting the service modules with other modules
**/
function dispBoardAdminBoardAdditionSetup() {
// Fix missing module configuration values
BoardModel::fixModuleConfig($this->module_info);
// sice content is obtained from other modules via call by reference, declare it first
$content = '';

View file

@ -20,6 +20,9 @@ class BoardController extends Board
throw new Rhymix\Framework\Exceptions\NotPermitted;
}
// Fix any missing module configurations
BoardModel::fixModuleConfig($this->module_info);
// setup variables
$obj = Context::getRequestVars();
$obj->module_srl = $this->module_srl;
@ -27,7 +30,7 @@ class BoardController extends Board
unset($obj->extra_vars);
// Remove disallowed Unicode symbols.
if ($this->module_info->filter_specialchars !== 'N')
if ($this->module_info->filter_specialchars === 'Y')
{
if (isset($obj->title))
{
@ -50,14 +53,14 @@ class BoardController extends Board
}
// Return error if content is too large.
$document_length_limit = ($this->module_info->document_length_limit ?: 1024) * 1024;
$document_length_limit = $this->module_info->document_length_limit * 1024;
if (strlen($obj->content) > $document_length_limit && !$this->grant->manager)
{
throw new Rhymix\Framework\Exception('msg_content_too_long');
}
// Return error if content conains excessively large data URLs.
$inline_data_url_limit = ($this->module_info->inline_data_url_limit ?: 64) * 1024;
$inline_data_url_limit = $this->module_info->inline_data_url_limit * 1024;
preg_match_all('!src="\s*(data:[^,]*,[a-z0-9+/=%$!._-]+)!i', (string)$obj->content, $matches);
foreach ($matches[1] as $match)
{
@ -85,7 +88,7 @@ class BoardController extends Board
$obj->category_srl = 0;
}
}
if (!$obj->category_srl && ($this->module_info->allow_no_category ?? 'N') !== 'Y')
if (!$obj->category_srl && $this->module_info->allow_no_category !== 'Y')
{
if (!$this->grant->manager)
{
@ -135,7 +138,7 @@ class BoardController extends Board
$oDocument = DocumentModel::getDocument($obj->document_srl);
// Set anonymous information when insert mode or status is temp
if($this->module_info->use_anonymous == 'Y' && (!$this->grant->manager || ($this->module_info->anonymous_except_admin ?? 'N') !== 'Y') && (!$oDocument->isExists() || $oDocument->get('status') == DocumentModel::getConfigStatus('temp')))
if($this->module_info->use_anonymous == 'Y' && (!$this->grant->manager || $this->module_info->anonymous_except_admin === 'N') && (!$oDocument->isExists() || $oDocument->get('status') == DocumentModel::getConfigStatus('temp')))
{
if(!$obj->document_srl)
{
@ -143,7 +146,7 @@ class BoardController extends Board
}
$manual = true;
$anonymous_name = $this->module_info->anonymous_name ?: 'anonymous';
$anonymous_name = $this->module_info->anonymous_name ?: BoardModel::DEFAULT_MODULE_CONFIG['anonymous_name'];
$anonymous_name = $this->createAnonymousName($anonymous_name, $logged_info->member_srl, $obj->document_srl);
$obj->notify_message = 'N';
@ -172,7 +175,7 @@ class BoardController extends Board
}
// Protect admin document
if ($this->module_info->protect_admin_content_update !== 'N')
if ($this->module_info->protect_admin_content_update === 'Y')
{
$member_info = MemberModel::getMemberInfo($oDocument->get('member_srl'));
if($member_info->is_admin == 'Y' && $logged_info->is_admin != 'Y')
@ -361,6 +364,9 @@ class BoardController extends Board
throw new Rhymix\Framework\Exceptions\NotPermitted;
}
// Fix any missing module configurations
BoardModel::fixModuleConfig($this->module_info);
// check protect content
if($this->module_info->protect_content == 'Y' || $this->module_info->protect_delete_content == 'Y')
{
@ -370,7 +376,7 @@ class BoardController extends Board
}
}
if ($this->module_info->protect_admin_content_delete !== 'N' && $this->user->is_admin !== 'Y')
if ($this->module_info->protect_admin_content_delete === 'Y' && $this->user->is_admin !== 'Y')
{
$member_info = MemberModel::getMemberInfo($oDocument->get('member_srl'));
if($member_info->is_admin === 'Y')
@ -462,8 +468,11 @@ class BoardController extends Board
// Comments belong in the same module_srl as the document.
$obj->module_srl = $oDocument->get('module_srl');
// Fix any missing module configurations
BoardModel::fixModuleConfig($this->module_info);
// Remove disallowed Unicode symbols.
if ($this->module_info->filter_specialchars !== 'N')
if ($this->module_info->filter_specialchars === 'Y')
{
if (isset($obj->content))
{
@ -495,12 +504,14 @@ class BoardController extends Board
}
}
if(!$this->module_info->use_status) $this->module_info->use_status = 'PUBLIC';
if(!$this->module_info->use_status)
{
$this->module_info->use_status = 'PUBLIC';
}
if(!is_array($this->module_info->use_status))
{
$this->module_info->use_status = explode('|@|', $this->module_info->use_status);
}
if(in_array('SECRET', $this->module_info->use_status))
{
$this->module_info->secret = 'Y';
@ -512,7 +523,7 @@ class BoardController extends Board
}
// For anonymous use, remove writer's information and notifying information
if($this->module_info->use_anonymous == 'Y' && (!$this->grant->manager || ($this->module_info->anonymous_except_admin ?? 'N') !== 'Y'))
if($this->module_info->use_anonymous == 'Y' && (!$this->grant->manager || $this->module_info->anonymous_except_admin === 'N'))
{
$obj->notify_message = 'N';
$obj->member_srl = -1*$logged_info->member_srl;
@ -547,7 +558,7 @@ class BoardController extends Board
}
}
if ($this->module_info->protect_admin_content_update !== 'N')
if ($this->module_info->protect_admin_content_update === 'Y')
{
$member_info = MemberModel::getMemberInfo($comment->member_srl);
if($member_info->is_admin == 'Y' && $logged_info->is_admin != 'Y')
@ -651,6 +662,9 @@ class BoardController extends Board
throw new Rhymix\Framework\Exceptions\NotPermitted;
}
// Fix any missing module configurations
BoardModel::fixModuleConfig($this->module_info);
$childs = null;
if($this->module_info->protect_delete_comment === 'Y' && $this->grant->manager == false)
{
@ -661,7 +675,7 @@ class BoardController extends Board
}
}
if ($this->module_info->protect_admin_content_delete !== 'N' && $this->user->is_admin !== 'Y')
if ($this->module_info->protect_admin_content_delete === 'Y' && $this->user->is_admin !== 'Y')
{
$member_info = MemberModel::getMemberInfo($comment->get('member_srl'));
if($member_info->is_admin === 'Y')

View file

@ -8,6 +8,101 @@
*/
class BoardModel extends Board
{
/**
* Default cofiguration for each module instance.
*/
public const DEFAULT_MODULE_CONFIG = [
// Title and SEO settings
'browser_title' => '',
'meta_keywords' => '',
'meta_description' => '',
'robots_tag' => 'all',
// PC and common display settings
'layout_srl' => -1,
'skin' => '/USE_DEFAULT/',
'list_count' => 20,
'search_list_count' => 20,
'page_count' => 10,
'header_text' => '',
'footer_text' => '',
// Mobile display settings
'use_mobile' => 'N',
'mlayout_srl' => -2,
'mskin' => '/USE_DEFAULT/',
'mobile_list_count' => 20,
'mobile_search_list_count' => 20,
'mobile_page_count' => 5,
'mobile_header_text' => '',
'mobile_footer_text' => '',
// List settings
'order_target' => 'list_order',
'order_type' => 'asc',
'except_notice' => 'Y',
'use_bottom_list' => 'Y',
'skip_bottom_list_for_olddoc' => 'N',
'skip_bottom_list_days' => 30,
'skip_bottom_list_for_robot' => 'Y',
// Feature settings
'consultation' => 'N',
'use_anonymous' => 'N',
'anonymous_except_admin' => 'N',
'anonymous_name' => 'anonymous',
'update_log' => 'N',
'update_order_on_comment' => 'N',
'comment_delete_message' => 'no',
'trash_use' => 'N',
'use_status' => 'PUBLIC',
'use_category' => 'N',
'allow_no_category' => 'N',
// Limits and protections
'document_length_limit' => 1024,
'comment_length_limit' => 128,
'inline_data_url_limit' => 64,
'filter_specialchars' => 'Y',
'protect_delete_content' => 'N',
'protect_update_content' => 'N',
'protect_delete_comment' => 'N',
'protect_update_comment' => 'N',
'protect_admin_content_delete' => 'Y',
'protect_admin_content_update' => 'Y',
'protect_document_regdate' => '',
'protect_comment_regdate' => '',
// Extra settings
'admin_mail' => '',
'module_category_srl' => 0,
'description' => '',
];
/**
* Fix module configuration so that there are no missing values.
*
* The return value will be set to true if any values were added.
* The object will be modified in place.
*
* @param object $module_info
* @return bool
*/
public static function fixModuleConfig(object $module_info): bool
{
$fixed = false;
foreach (self::DEFAULT_MODULE_CONFIG as $key => $value)
{
if (!isset($module_info->{$key}))
{
$module_info->{$key} = $value;
$fixed = true;
}
}
return $fixed;
}
/**
* @brief get the list configuration
*/

View file

@ -852,10 +852,13 @@ class BoardView extends Board
return $this->dispBoardMessage($this->user->isMember() ? 'msg_not_permitted' : 'msg_not_logged');
}
// Fix any missing module configurations
BoardModel::fixModuleConfig($this->module_info);
/**
* check if the category option is enabled not not
*/
if($this->module_info->use_category=='Y')
if ($this->module_info->use_category === 'Y')
{
// get the user group information
if(Context::get('is_logged'))
@ -866,7 +869,6 @@ class BoardView extends Board
{
$group_srls = array();
}
$group_srls_count = count($group_srls);
// check the grant after obtained the category list
$category_list = array();
@ -916,9 +918,9 @@ class BoardView extends Board
$oDocument->add('origin_module_srl', $oDocument->get('module_srl'));
$oDocument->add('module_srl', $this->module_srl);
if($oDocument->isExists())
if ($oDocument->isExists())
{
if(($this->module_info->protect_document_regdate ?? 0) > 0 && $this->grant->manager == false)
if ($this->module_info->protect_document_regdate > 0 && $this->grant->manager == false)
{
if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day')))
{
@ -927,7 +929,7 @@ class BoardView extends Board
throw new Rhymix\Framework\Exception($massage);
}
}
if(($this->module_info->protect_content ?? 'N') === 'Y' || ($this->module_info->protect_update_content ?? 'N') == 'Y')
if ($this->module_info->protect_content === 'Y' || $this->module_info->protect_update_content === 'Y')
{
if($oDocument->get('comment_count') > 0 && $this->grant->manager == false)
{
@ -935,7 +937,7 @@ class BoardView extends Board
}
}
if (($this->module_info->protect_admin_content_update ?? 'N') !== 'N')
if ($this->module_info->protect_admin_content_update === 'Y')
{
$member_info = MemberModel::getMemberInfo($oDocument->get('member_srl'));
if(isset($member_info->is_admin) && $member_info->is_admin == 'Y' && $this->user->is_admin != 'Y')
@ -1081,6 +1083,9 @@ class BoardView extends Board
}
}
// Fix any missing module configurations
BoardModel::fixModuleConfig($this->module_info);
if($this->module_info->protect_document_regdate > 0 && $this->grant->manager == false)
{
if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day')))
@ -1275,6 +1280,9 @@ class BoardView extends Board
}
}
// Fix any missing module configurations
BoardModel::fixModuleConfig($this->module_info);
if($this->module_info->protect_comment_regdate > 0 && $this->grant->manager == false)
{
if($oComment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day')))
@ -1359,6 +1367,9 @@ class BoardView extends Board
}
}
// Fix any missing module configurations
BoardModel::fixModuleConfig($this->module_info);
if($this->module_info->protect_comment_regdate > 0 && $this->grant->manager == false)
{
if($oComment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day')))

View file

@ -66,7 +66,7 @@
<div class="x_controls">
<select name="layout_srl" id="layout_srl">
<option value="0">{$lang->notuse}</option>
<option loop="$layout_list => $key, $val" value="{$val->layout_srl}" selected="selected"|cond="$module_info->layout_srl== $val->layout_srl">{$val->title} ({$val->layout})</option>
<option loop="$layout_list => $key, $val" value="{$val->layout_srl}" selected="selected"|cond="$module_info->layout_srl == $val->layout_srl">{$val->title} ({$val->layout})</option>
</select>
<a href="#layout_help" class="x_icon-question-sign" data-toggle>{$lang->help}</a>
<p id="layout_help" class="x_help-block x_hide">{$lang->about_layout}</p>
@ -76,28 +76,28 @@
<label class="x_control-label" for="skin">{$lang->skin}</label>
<div class="x_controls">
<select name="skin" id="skin" style="width:auto">
<option loop="$skin_list=> $key, $val" value="{$key}" selected="selected"|cond="$module_info->skin== $key || (!$module_info->skin && $key=='default')">{$val->title}</option>
<option loop="$skin_list=> $key, $val" value="{$key}" selected="selected"|cond="$module_info->skin == $key || (!$module_info->skin && $key == 'default')">{$val->title}</option>
</select>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="list_count">{$lang->list_count}</label>
<div class="x_controls">
<input type="number" min="1" name="list_count" id="list_count" value="{$module_info->list_count?$module_info->list_count:20}" />
<input type="number" min="1" name="list_count" id="list_count" value="{$module_info->list_count ?: BoardModel::DEFAULT_MODULE_CONFIG['list_count']}" />
<p class="x_help-inline">{$lang->about_list_count}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="search_list_count">{$lang->search_list_count}</label>
<div class="x_controls">
<input type="number" min="1" name="search_list_count" id="search_list_count" value="{$module_info->search_list_count?$module_info->search_list_count:20}" />
<input type="number" min="1" name="search_list_count" id="search_list_count" value="{$module_info->search_list_count ?: BoardModel::DEFAULT_MODULE_CONFIG['search_list_count']}" />
<p class="x_help-inline">{$lang->about_search_list_count}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="page_count">{$lang->page_count}</label>
<div class="x_controls">
<input type="number" min="1" name="page_count" id="page_count" value="{$module_info->page_count?$module_info->page_count:10}" />
<input type="number" min="1" name="page_count" id="page_count" value="{$module_info->page_count ?: BoardModel::DEFAULT_MODULE_CONFIG['page_count']}" />
<p class="x_help-inline">{$lang->about_page_count}</p>
</div>
</div>
@ -138,7 +138,7 @@
<div class="x_controls">
<select name="mlayout_srl" id="mlayout_srl">
<option value="0">{$lang->notuse}</option>
<option loop="$mlayout_list => $key, $val" value="{$val->layout_srl}" selected="selected"|cond="$module_info->mlayout_srl== $val->layout_srl">{$val->title} <block cond="$val->layout">({$val->layout})</block></option>
<option loop="$mlayout_list => $key, $val" value="{$val->layout_srl}" selected="selected"|cond="$module_info->mlayout_srl == $val->layout_srl">{$val->title} <block cond="$val->layout">({$val->layout})</block></option>
</select>
<a href="#mobile_layout_help" class="x_icon-question-sign" data-toggle>{$lang->help}</a>
<p id="mobile_layout_help" class="x_help-block x_hide">{$lang->about_layout}</p>
@ -148,7 +148,7 @@
<label class="x_control-label" for="mskin">{$lang->mobile_skin}</label>
<div class="x_controls">
<select name="mskin" id="mskin">
<option loop="$mskin_list=> $key, $val" value="{$key}" selected="selected"|cond="$module_info->mskin== $key || (!$module_info->skin && $key=='default')">{$val->title}</option>
<option loop="$mskin_list=> $key, $val" value="{$key}" selected="selected"|cond="$module_info->mskin == $key || (!$module_info->skin && $key == 'default')">{$val->title}</option>
</select>
<a href="#mobile_skin_help" class="x_icon-question-sign" data-toggle>{$lang->help}</a>
<p id="mobile_skin_help" class="x_help-block x_hide">{$lang->about_skin}</p>
@ -157,21 +157,21 @@
<div class="x_control-group">
<label class="x_control-label" for="mobile_list_count">{$lang->list_count}</label>
<div class="x_controls">
<input type="number" min="1" name="mobile_list_count" id="mobile_list_count" value="{$module_info->mobile_list_count?$module_info->mobile_list_count:20}" />
<input type="number" min="1" name="mobile_list_count" id="mobile_list_count" value="{$module_info->mobile_list_count ?: BoardModel::DEFAULT_MODULE_CONFIG['mobile_list_count']}" />
<p class="x_help-inline">{$lang->about_list_count}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="mobile_search_list_count">{$lang->search_list_count}</label>
<div class="x_controls">
<input type="number" min="1" name="mobile_search_list_count" id="mobile_search_list_count" value="{$module_info->mobile_search_list_count?$module_info->mobile_search_list_count:20}" />
<input type="number" min="1" name="mobile_search_list_count" id="mobile_search_list_count" value="{$module_info->mobile_search_list_count ?: BoardModel::DEFAULT_MODULE_CONFIG['mobile_search_list_count']}" />
<p class="x_help-inline">{$lang->about_search_list_count}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="mobile_page_count">{$lang->page_count}</label>
<div class="x_controls">
<input type="number" min="1" name="mobile_page_count" id="mobile_page_count" value="{$module_info->mobile_page_count?$module_info->mobile_page_count:5}" />
<input type="number" min="1" name="mobile_page_count" id="mobile_page_count" value="{$module_info->mobile_page_count ?: BoardModel::DEFAULT_MODULE_CONFIG['mobile_page_count']}" />
<p class="x_help-inline">{$lang->about_mobile_page_count}</p>
</div>
</div>
@ -224,9 +224,9 @@
<label class="x_control-label">{$lang->order_type}</label>
<div class="x_controls">
<select name="order_target" id="order_target" title="{$lang->order_target}">
<option loop="$order_target=> $key, $val" value="{$key}" selected="selected"|cond="$module_info->order_target== $key">{$val}</option>
<option loop="$order_target=> $key, $val" value="{$key}" selected="selected"|cond="$module_info->order_target == $key">{$val}</option>
<block cond="$extra_order_target">
<option loop="$extra_order_target=> $key, $val" value="{$key}" selected="selected"|cond="$module_info->order_target== $key">{Context::replaceUserLang($val)}</option>
<option loop="$extra_order_target=> $key, $val" value="{$key}" selected="selected"|cond="$module_info->order_target == $key">{Context::replaceUserLang($val)}</option>
</block>
</select>
<select name="order_type" id="order_type" title="{$lang->order_type}">
@ -293,28 +293,28 @@
<div class="x_control-group">
<label class="x_control-label">{$lang->anonymous_name}</label>
<div class="x_controls">
<input type="text" name="anonymous_name" id="anonymous_name" value="{$module_info->anonymous_name ?: 'anonymous'}" />
<input type="text" name="anonymous_name" id="anonymous_name" value="{$module_info->anonymous_name ?: BoardModel::DEFAULT_MODULE_CONFIG['anonymous_name']}" />
<p class="x_help-block">{$lang->about_anonymous_name}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->document_length_limit}</label>
<div class="x_controls">
<input type="number" min="1" name="document_length_limit" id="document_length_limit" value="{$module_info->document_length_limit ?: 1024}" /> KB
<input type="number" min="1" name="document_length_limit" id="document_length_limit" value="{$module_info->document_length_limit ?: BoardModel::DEFAULT_MODULE_CONFIG['document_length_limit']}" /> KB
<p class="x_help-block">{$lang->about_document_length_limit}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->comment_length_limit}</label>
<div class="x_controls">
<input type="number" min="1" name="comment_length_limit" id="comment_length_limit" value="{$module_info->comment_length_limit ?: 128}" /> KB
<input type="number" min="1" name="comment_length_limit" id="comment_length_limit" value="{$module_info->comment_length_limit ?: BoardModel::DEFAULT_MODULE_CONFIG['comment_length_limit']}" /> KB
<p class="x_help-block">{$lang->about_comment_length_limit}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->inline_data_url_limit}</label>
<div class="x_controls">
<input type="number" min="1" name="inline_data_url_limit" id="inline_data_url_limit" value="{$module_info->inline_data_url_limit ?: 64}" /> KB
<input type="number" min="1" name="inline_data_url_limit" id="inline_data_url_limit" value="{$module_info->inline_data_url_limit ?: BoardModel::DEFAULT_MODULE_CONFIG['inline_data_url_limit']}" /> KB
<p class="x_help-block">{$lang->about_inline_data_url_limit}</p>
</div>
</div>

View file

@ -2,15 +2,15 @@
<div class="x_page-header">
<h1>
{$lang->board_management}
<span class="path" cond="$module_info->mid">
&gt; <a href="{getSiteUrl($module_info->domain ?? '', '', 'mid', $module_info->mid)}" target="_blank"|cond="$module=='admin'">{$module_info->mid}<block cond="$module_info->is_default=='Y'">({$lang->is_default})</block></a>
<span class="path" cond="!empty($module_info->mid)">
&gt; <a href="{getSiteUrl($module_info->domain ?? '', '', 'mid', $module_info->mid)}" target="_blank"|cond="Context::get('module') == 'admin'">{$module_info->mid}<block cond="$module_info->is_default == 'Y'">({$lang->is_default})</block></a>
</span>
<a href="#aboutModule" data-toggle class="x_icon-question-sign">{$lang->help}</a>
</h1>
</div>
<p class="x_alert x_alert-info x_hide" id="aboutModule">{$lang->about_board}</p>
<ul class="x_nav x_nav-tabs" cond="$module_info && $act != 'dispBoardAdminContent' && $act != 'dispBoardAdminDeleteBoard'">
<li cond="$module=='admin'" class="x_active"|cond="$act=='dispBoardAdminContent'"><a href="{getUrl('act','dispBoardAdminContent','module_srl','', 'selected_var_idx', '', 'type', '')}">{$lang->cmd_board_list}</a></li>
<li cond="Context::get('module') == 'admin'" class="x_active"|cond="$act=='dispBoardAdminContent'"><a href="{getUrl('act','dispBoardAdminContent','module_srl','', 'selected_var_idx', '', 'type', '')}">{$lang->cmd_board_list}</a></li>
<!--<li class="x_active" cond="$act=='dispBoardAdminInsertBoard'"><a href="{getUrl('act','dispBoardAdminInsertBoard', 'selected_var_idx', '', 'type', '')}">{$lang->cmd_create_board}</a></li>-->
<li cond="$module_srl" class="x_active"|cond="$act=='dispBoardAdminBoardInfo'"><a href="{getUrl('act','dispBoardAdminBoardInfo', 'selected_var_idx', '', 'type', '')}">{$lang->cmd_board_info}</a></li>
<li cond="$module_srl" class="x_active"|cond="$act=='dispBoardAdminCategoryInfo'"><a href="{getUrl('act','dispBoardAdminCategoryInfo', 'selected_var_idx', '', 'type', '')}">{$lang->cmd_manage_category}</a></li>