diff --git a/core/ajax/cache.ajax.php b/core/ajax/cache.ajax.php index ee5b5baef7..bb7a56e802 100644 --- a/core/ajax/cache.ajax.php +++ b/core/ajax/cache.ajax.php @@ -28,7 +28,7 @@ if (init('action') == 'set') { unautorizedInDemo(); - cache::set(init('key'), init('value'), init('lifetime', 0), init('options', null)); + cache::set(init('key'), init('value'), init('lifetime', 0)); ajax::success(); } diff --git a/core/ajax/cmd.ajax.php b/core/ajax/cmd.ajax.php index 9b858a2dbc..e0b7d7f077 100644 --- a/core/ajax/cmd.ajax.php +++ b/core/ajax/cmd.ajax.php @@ -465,7 +465,7 @@ $data[] = $info_history; } } else { - $histories = history::getHistoryFromCalcul(jeedom::fromHumanReadable(init('id')), $dateStart, $dateEnd, init('allowZero', false), init('groupingType'), init('addFirstPreviousValue', false)); + $histories = history::getHistoryFromCalcul(jeedom::fromHumanReadable(init('id')), $dateStart, $dateEnd, init('allowZero', false), init('groupingType')); if (is_array($histories)) { foreach ($histories as $datetime => $value) { $info_history = array(); diff --git a/core/ajax/eqLogic.ajax.php b/core/ajax/eqLogic.ajax.php index 99f30677e3..2226aedc32 100644 --- a/core/ajax/eqLogic.ajax.php +++ b/core/ajax/eqLogic.ajax.php @@ -541,7 +541,7 @@ $eqLogicsSave = json_decode($eqLogicSaves, true); $nbrSave = count($eqLogicsSave); $return = array(); - + $eqLogic = null; foreach ($eqLogicsSave as $eqLogicSave) { if (!is_array($eqLogicSave)) { diff --git a/core/ajax/interact.ajax.php b/core/ajax/interact.ajax.php index 31ad3f4008..cf022a81bf 100644 --- a/core/ajax/interact.ajax.php +++ b/core/ajax/interact.ajax.php @@ -30,7 +30,7 @@ $results = utils::o2a(interactDef::all()); foreach ($results as &$result) { $result['nbInteractQuery'] = count(interactQuery::byInteractDefId($result['id'])); - $result['nbEnableInteractQuery'] = count(interactQuery::byInteractDefId($result['id'], true)); + $result['nbEnableInteractQuery'] = count(interactQuery::byInteractDefId($result['id'])); if (isset($result['link_type']) && $result['link_type'] == 'cmd' && $result['link_id'] != '') { $link_id = ''; foreach (explode('&&', $result['link_id']) as $cmd_id) { @@ -49,7 +49,7 @@ if (init('action') == 'byId') { $result = utils::o2a(interactDef::byId(init('id'))); $result['nbInteractQuery'] = count(interactQuery::byInteractDefId($result['id'])); - $result['nbEnableInteractQuery'] = count(interactQuery::byInteractDefId($result['id'], true)); + $result['nbEnableInteractQuery'] = count(interactQuery::byInteractDefId($result['id'])); ajax::success(jeedom::toHumanReadable($result)); } diff --git a/core/ajax/listener.ajax.php b/core/ajax/listener.ajax.php index e0abe1d9d1..59144059eb 100644 --- a/core/ajax/listener.ajax.php +++ b/core/ajax/listener.ajax.php @@ -43,7 +43,7 @@ } if (init('action') == 'all') { - $listeners = utils::o2a(listener::all(true)); + $listeners = utils::o2a(listener::all()); foreach ($listeners as &$listener) { $listener['event_str'] = ''; foreach ($listener['event'] as $event) { diff --git a/core/ajax/object.ajax.php b/core/ajax/object.ajax.php index 43eac0e1f9..da8ec2bed6 100644 --- a/core/ajax/object.ajax.php +++ b/core/ajax/object.ajax.php @@ -231,7 +231,7 @@ function jeeAjax_objectToHtml($_id = -1, $_version = 'dashboard', $_category = ' if (!isConnect('admin')) { throw new Exception(__('401 - Accès non autorisé', __FILE__)); } - ajax::success(jeeObject::getUISelectList(init('none'), true)); + ajax::success(jeeObject::getUISelectList(init('none'))); } if (init('action') == 'getSummaryHtml') { diff --git a/core/ajax/queue.ajax.php b/core/ajax/queue.ajax.php index 3e094df417..e5957904d6 100644 --- a/core/ajax/queue.ajax.php +++ b/core/ajax/queue.ajax.php @@ -43,7 +43,7 @@ } if (init('action') == 'all') { - $queues = queue::all(true); + $queues = queue::all(); foreach ($queues as $queue) { $queue->refresh(); } diff --git a/core/ajax/report.ajax.php b/core/ajax/report.ajax.php index 178b0dc16d..9d3c7b0cd7 100644 --- a/core/ajax/report.ajax.php +++ b/core/ajax/report.ajax.php @@ -61,7 +61,7 @@ foreach (ls($path, '*') as $value) { unlink($path . $value); } - ajax::success($return); + ajax::success(); } throw new Exception(__('Aucune méthode correspondante à :', __FILE__) . ' ' . init('action')); diff --git a/core/ajax/scenario.ajax.php b/core/ajax/scenario.ajax.php index 25b199c7cf..eedce347b4 100644 --- a/core/ajax/scenario.ajax.php +++ b/core/ajax/scenario.ajax.php @@ -183,6 +183,7 @@ if (init('action') == 'applyTemplate') { unautorizedInDemo(); $path = __DIR__ . '/../../data/scenario'; + $converts = []; if (!file_exists($path . '/' . init('template'))) { throw new Exception(__('Fichier non trouvé :', __FILE__) . ' ' . $path . '/' . init('template')); } diff --git a/core/ajax/user.ajax.php b/core/ajax/user.ajax.php index 8cb6103efb..8bd1e72a89 100644 --- a/core/ajax/user.ajax.php +++ b/core/ajax/user.ajax.php @@ -37,6 +37,7 @@ if (!isConnect()) { if (config::byKey('sso:allowRemoteUser') == 1) { + $configs = config::byKeys(array('session_lifetime', 'sso:allowRemoteUser', 'sso:remoteUserHeader')); $header = $configs['sso:remoteUserHeader']; $header_value = $_SERVER[$header]; $user = user::byLogin($header_value); @@ -343,7 +344,8 @@ if (init('action') == 'removeBanIp') { unautorizedInDemo(); - ajax::success(user::removeBanIp()); + user::removeBanIp(); + ajax::success(); } if (init('action') == 'supportAccess') { diff --git a/core/api/jeeApi.php b/core/api/jeeApi.php index f479948485..f6c87b055b 100644 --- a/core/api/jeeApi.php +++ b/core/api/jeeApi.php @@ -416,7 +416,7 @@ if (is_object($_USER_GLOBAL) && $_USER_GLOBAL->getProfils() != 'admin') { throw new Exception(__('Vous n\'êtes pas autorisé à effectuer cette action', __FILE__) . ' ' . $jsonrpc->getMethod(), -32001); } - jeedom::update($params['options'], 0); + jeedom::update($params['options']); $jsonrpc->makeSuccess('ok'); } @@ -497,6 +497,7 @@ throw new Exception(__('Vous n\'avez pas les droits de faire cette action', __FILE__), -32701); } unautorizedInDemo(); + $object = null; if (isset($params['id'])) { $object = jeeObject::byId($params['id']); } @@ -836,6 +837,7 @@ if ($jsonrpc->getMethod() == 'cmd::save') { unautorizedInDemo(); + $cmd = null; if (isset($params['id'])) { $cmd = cmd::byId($params['id']); if (is_object($_USER_GLOBAL) && !$cmd->hasRight($_USER_GLOBAL)) { @@ -979,6 +981,7 @@ if ($jsonrpc->getMethod() == 'scenario::save') { unautorizedInDemo(); + $scenario = null; if (isset($params['id'])) { $scenario = scenario::byId($params['id']); } @@ -1152,6 +1155,7 @@ throw new Exception(__('Vous n\'avez pas les droits de faire cette action', __FILE__), -32701); } unautorizedInDemo(); + $update = null; if (isset($params['plugin_id'])) { $update = update::byId($params['plugin_id']); } @@ -1277,7 +1281,7 @@ throw new Exception(__('Vous n\'avez pas les droits de faire cette action', __FILE__), -32701); } unautorizedInDemo(); - jeedom::update('', 0); + jeedom::update(''); $jsonrpc->makeSuccess('ok'); } @@ -1294,6 +1298,7 @@ throw new Exception(__('Vous n\'avez pas les droits de faire cette action', __FILE__), -32701); } unautorizedInDemo(); + $update = null; if (isset($params['plugin_id'])) { $update = update::byId($params['plugin_id']); } diff --git a/core/api/proApi.php b/core/api/proApi.php index 180eb02087..49224fc65e 100644 --- a/core/api/proApi.php +++ b/core/api/proApi.php @@ -643,7 +643,7 @@ } if ($jsonrpc->getMethod() == 'jeeNetwork::update') { - jeedom::update('', 0); + jeedom::update(''); $jsonrpc->makeSuccess('ok'); } @@ -751,7 +751,7 @@ } if ($jsonrpc->getMethod() == 'backup::restoreMarket') { - repo_market::backup_restore($params['backup'], true); + repo_market::backup_restore($params['backup']); $jsonrpc->makeSuccess(); } @@ -815,9 +815,9 @@ /* * ************************Plugin*************************** */ if ($jsonrpc->getMethod() == 'plugin::install') { try { - $market = market::byId($params['plugin_id']); + $market = repo_market::byId($params['plugin_id']); } catch (Exception $e) { - $market = market::byLogicalId($params['plugin_id']); + $market = repo_market::byLogicalId($params['plugin_id']); } if (!is_object($market)) { throw new Exception(__('Impossible de trouver l\'objet associé :', __FILE__) . ' ' . secureXSS($params['plugin_id'])); @@ -830,7 +830,7 @@ } if ($jsonrpc->getMethod() == 'plugin::remove') { - $market = market::byId($params['plugin_id']); + $market = repo_market::byId($params['plugin_id']); if (!is_object($market)) { throw new Exception(__('Impossible de trouver l\'objet associé :', __FILE__) . ' ' . secureXSS($params['plugin_id'])); } @@ -858,7 +858,7 @@ } if ($jsonrpc->getMethod() == 'update::update') { - jeedom::update('', 0); + jeedom::update(''); $jsonrpc->makeSuccess('ok'); } diff --git a/core/class/cmd.class.php b/core/class/cmd.class.php index 9000d3935f..ea11a862c3 100644 --- a/core/class/cmd.class.php +++ b/core/class/cmd.class.php @@ -2326,7 +2326,7 @@ public function pushInflux($_value = null) { return; } - public function dropInfluxDatabase() { + public static function dropInfluxDatabase() { try { $database = cmd::getInflux(); if ($database == '') { @@ -2354,8 +2354,15 @@ public function dropInflux() { return; } - public function historyInfluxAll() { - cmd::historyInflux('all'); + public static function historyInfluxAll() { + $cron = new cron(); + $cron->setClass('cmd'); + $cron->setFunction('sendHistoryInflux'); + $cron->setOption(array('cmd_id' => 'all')); + $cron->setLastRun(date('Y-m-d H:i:s')); + $cron->setOnce(1); + $cron->setSchedule(cron::convertDateToCron(strtotime("now") + 60)); + $cron->save(); } public static function sendHistoryInflux($_params) { diff --git a/core/class/event.class.php b/core/class/event.class.php index c603a7487d..70939c4c15 100644 --- a/core/class/event.class.php +++ b/core/class/event.class.php @@ -19,6 +19,10 @@ /* * ***************************Includes********************************* */ require_once __DIR__ . '/../../core/php/core.inc.php'; +/** + * @see https://github.com/phpstan/phpstan/issues/13556 + * @method static void add(string $_event, $_option = [], bool $_clean = true) + */ class event { /* * *************************Attributs****************************** */ diff --git a/core/class/history.class.php b/core/class/history.class.php index 9c9e4dcd6b..45496d5c91 100644 --- a/core/class/history.class.php +++ b/core/class/history.class.php @@ -366,6 +366,7 @@ public static function all($_cmd_id, $_startTime = null, $_endTime = null, $_gro $values['endTime'] = $_endTime; } $sql=''; + $goupingType = []; if ($_groupingType == null || strpos($_groupingType, '::') === false) { $sql .= 'SELECT ' . DB::buildField(__CLASS__); } else { diff --git a/core/class/interactQuery.class.php b/core/class/interactQuery.class.php index be5117a895..a6d2350cf3 100644 --- a/core/class/interactQuery.class.php +++ b/core/class/interactQuery.class.php @@ -116,6 +116,7 @@ public static function removeByInteractDefId($_interactDef_id) { } public static function recognize($_query) { + $closest = null; $_query = trim(interactDef::sanitizeQuery($_query)); if (trim($_query) == '') { return null; @@ -248,6 +249,7 @@ public static function findInQuery($_type, $_query, $_data = null) { $return['query'] = strtolower(sanitizeAccent($_query)); $return[$_type] = null; $synonyms = self::getQuerySynonym($return['query'], $_type); + $objects = []; if ($_type == 'object') { $objects = jeeObject::all(); } elseif ($_type == 'eqLogic') { @@ -332,6 +334,7 @@ public static function autoInteract($_query, $_parameters = array()) { $data = array_merge($data, self::findInQuery('eqLogic', $data['query'], $data)); $data = array_merge($data, self::findInQuery('cmd', $data['query'], $data)); if (isset($data['eqLogic']) && is_object($data['eqLogic']) && (!isset($data['cmd']) || !is_object($data['cmd']))) { + $cmd = null; foreach ($data['eqLogic']->getCmd('action') as $cmd) { if ($cmd->getSubtype() == 'slider') { break; @@ -667,7 +670,7 @@ public static function contextualReply($_query, $_parameters = array(), $_lastCm return $return; } - public function replaceForContextual($_replace, $_by, $_in) { + public static function replaceForContextual($_replace, $_by, $_in) { return str_replace(strtolower(sanitizeAccent($_replace)), strtolower(sanitizeAccent($_by)), str_replace($_replace, $_by, $_in)); } diff --git a/core/class/jeeObject.class.php b/core/class/jeeObject.class.php index 39f6884f0a..661736087e 100644 --- a/core/class/jeeObject.class.php +++ b/core/class/jeeObject.class.php @@ -296,6 +296,7 @@ public static function checkSummaryUpdate($_cmd_id) { } $toRefreshCmd = array(); $global = array(); + $events = []; foreach ($objects as $object) { $summaries = $object->getConfiguration('summary'); if (!is_array($summaries)) { @@ -581,7 +582,7 @@ public static function createSummaryToVirtual($_key = '') { if (!$plugin->isActive()) { $plugin->setIsEnable(1); } - if (!is_object($plugin)) { + if (!is_object($plugin) || !class_exists('virtual') || !class_exists('virtualCmd')) { throw new Exception(__('Le plugin virtuel doit être installé', __FILE__)); } if (!$plugin->isActive()) { diff --git a/core/class/jsonrpcClient.class.php b/core/class/jsonrpcClient.class.php index 5a00138230..bee27bdbda 100644 --- a/core/class/jsonrpcClient.class.php +++ b/core/class/jsonrpcClient.class.php @@ -120,7 +120,7 @@ private function send($_request, $_timeout = 15, $_file = null, $_maxRetry = 2) } } $nbRetry = 0; - while ($nbRetry < $_maxRetry) { + do { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->apiAddr); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); @@ -140,19 +140,19 @@ private function send($_request, $_timeout = 15, $_file = null, $_maxRetry = 2) } if(config::byKey('proxyEnabled')) { if(config::byKey('proxyAddress') == ''){ - // throw new Exception(__('renseigne l\'adresse', __FILE__)); - $this->error = 'Erreur address '; - } else if (config::byKey('proxyPort') == ''){ - // throw new Exception(__('renseigne le port', __FILE__)); - } else { - curl_setopt($ch, CURLOPT_PROXY, config::byKey('proxyAddress')); - curl_setopt($ch, CURLOPT_PROXYPORT, config::byKey('proxyPort')); - if(!empty(config::byKey('proxyLogin') || config::byKey('proxyPassword'))){ - curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'proxyLogin:proxyPassword'); - } - log::add('Connection', 'debug', $ch); - } - } + // throw new Exception(__('renseigne l\'adresse', __FILE__)); + $this->error = 'Erreur address '; + } else if (config::byKey('proxyPort') == ''){ + // throw new Exception(__('renseigne le port', __FILE__)); + } else { + curl_setopt($ch, CURLOPT_PROXY, config::byKey('proxyAddress')); + curl_setopt($ch, CURLOPT_PROXYPORT, config::byKey('proxyPort')); + if(!empty(config::byKey('proxyLogin') || config::byKey('proxyPassword'))){ + curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'proxyLogin:proxyPassword'); + } + log::add('Connection', 'debug', $ch); + } + } $response = curl_exec($ch); $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); $nbRetry++; @@ -162,7 +162,7 @@ private function send($_request, $_timeout = 15, $_file = null, $_maxRetry = 2) } else { $nbRetry = $_maxRetry + 1; } - } + } while ($nbRetry < $_maxRetry); if ($http_status == 301) { if (preg_match('//i', $response, $r)) { $this->apiAddr = trim($r[1]); diff --git a/core/class/network.class.php b/core/class/network.class.php index 7958b1da78..219a2a90d4 100644 --- a/core/class/network.class.php +++ b/core/class/network.class.php @@ -328,7 +328,7 @@ public static function dns_create() { $update->doUpdate(); $plugin = plugin::byId('openvpn'); } - if (!is_object($plugin)) { + if (!is_object($plugin) || !class_exists('openvpn')) { throw new Exception(__('Le plugin OpenVPN doit être installé', __FILE__)); } if (!$plugin->isActive()) { diff --git a/core/class/plugin.class.php b/core/class/plugin.class.php index 8f43d1e354..cecfe40e1d 100644 --- a/core/class/plugin.class.php +++ b/core/class/plugin.class.php @@ -273,7 +273,7 @@ public static function listPlugin($_activateOnly = false, $_orderByCategory = fa } return $return; } else { - if (isset($listPlugin) && is_array($listPlugin) && count($listPlugin) > 0) { + if (is_array($listPlugin) && count($listPlugin) > 0) { usort($listPlugin, 'plugin::orderPlugin'); return $listPlugin; } else { diff --git a/core/class/scenario.class.php b/core/class/scenario.class.php index 2b96c67bec..2ea90582d4 100644 --- a/core/class/scenario.class.php +++ b/core/class/scenario.class.php @@ -1370,6 +1370,7 @@ public function export($_mode = 'text') { $return .= " " . $export . "\n"; } } + return $return; } if ($_mode == 'array') { $return = utils::o2a($this); @@ -1426,8 +1427,9 @@ public function export($_mode = 'text') { if (isset($return['_elements'])) { unset($return['_elements']); } + return $return; } - return $return; + return null; } /** * diff --git a/core/class/update.class.php b/core/class/update.class.php index c2b5062355..35cdb878c4 100644 --- a/core/class/update.class.php +++ b/core/class/update.class.php @@ -493,6 +493,7 @@ public function postInstallUpdate($_infos) { } public static function getLastAvailableVersion() { + $url = 'undefined url'; try { $url = 'https://raw.githubusercontent.com/jeedom/core/' . config::byKey('core::branch', 'core', 'master') . '/core/config/version'; $request_http = new com_http($url); @@ -515,7 +516,7 @@ public function checkUpdate() { return; } if (config::byKey('core::repo::provider') == 'default') { - $this->setRemoteVersion(self::getLastAvailableVersion(true)); + $this->setRemoteVersion(self::getLastAvailableVersion()); } else { $class = 'repo_' . config::byKey('core::repo::provider'); if (!method_exists($class, 'versionCore') || config::byKey(config::byKey('core::repo::provider') . '::enable') != 1) { diff --git a/core/class/utils.class.php b/core/class/utils.class.php index 57489aac2a..83310b90c5 100644 --- a/core/class/utils.class.php +++ b/core/class/utils.class.php @@ -178,6 +178,7 @@ public static function getJsonAttr(&$_attr, $_key = '', $_default = '') { } if (empty($_attr)) { if (is_array($_key)) { + $return = []; foreach ($_key as $key) { $return[$key] = $_default; } diff --git a/core/class/widgets.class.php b/core/class/widgets.class.php index 1cb729e000..7fea8ae343 100644 --- a/core/class/widgets.class.php +++ b/core/class/widgets.class.php @@ -31,6 +31,7 @@ class widgets { private $test; private $display; private $_changed = false; + protected $_needRefreshWidget = false; /* * ***********************Méthodes statiques*************************** */ diff --git a/core/config/jeedom.config.php b/core/config/jeedom.config.php index 3699788726..6faf7f63ee 100644 --- a/core/config/jeedom.config.php +++ b/core/config/jeedom.config.php @@ -383,10 +383,6 @@ 'name' => __('Thermostat minimum consigne', __FILE__), 'familyid' => 'Thermostat', 'family' => __('Thermostat', __FILE__), 'type' => 'Action', 'subtype' => array('slider') ), - 'THERMOSTAT_HUMIDITY' => array( - 'name' => __('Thermostat humidité ambiante', __FILE__), 'familyid' => 'Thermostat', 'family' => __('Thermostat', __FILE__), - 'type' => 'Info', 'subtype' => array('numeric'), 'calcul' => 'avg' - ), 'HUMIDITY_SETPOINT' => array( 'name' => __('Humidité consigne', __FILE__), 'familyid' => 'Thermostat', 'family' => __('Thermostat', __FILE__), 'type' => 'Info', 'subtype' => array('slider') diff --git a/core/php/utils.inc.php b/core/php/utils.inc.php index 08b0613c92..d6409a7345 100644 --- a/core/php/utils.inc.php +++ b/core/php/utils.inc.php @@ -206,7 +206,8 @@ function redirect($_url, $_forceType = null) { echo "window.location.href='$_url';"; echo ''; } else { - exit(header("Location: $_url")); + header("Location: $_url"); + exit; } return; } @@ -1159,15 +1160,14 @@ function evaluate($_string) { for ($i = 0; $i < $c; $i++) { $string = str_replace($matches[0][$i], '--preparsed' . $i . '--', $string); } - } else { - $c = 0; - } - $expr = preg_replace("/([^=<>!])=([^=])/", "$1==$2", $string); // Replace all '=' by '==' and avoid '==' '===' '>=' '<=' '!=' '!==' - if ($c > 0) { + + $expr = preg_replace("/([^=<>!])=([^=])/", "$1==$2", $string); // Replace all '=' by '==' and avoid '==' '===' '>=' '<=' '!=' '!==' for ($i = 0; $i < $c; $i++) { $expr = str_replace('--preparsed' . $i . '--', $matches[0][$i], $expr); } - } + } else { + $expr = preg_replace("/([^=<>!])=([^=])/", "$1==$2", $string); // Replace all '=' by '==' and avoid '==' '===' '>=' '<=' '!=' '!==' + } try { return $GLOBALS['ExpressionLanguage']->evaluate($expr); } catch (Exception $e) { @@ -1692,6 +1692,7 @@ function getTZoffsetMin() { } function pageTitle($_page) { + $return = $_page; switch ($_page) { case 'overview': $return = __('Synthèse', __FILE__); @@ -1786,9 +1787,6 @@ function pageTitle($_page) { $return = __('Panel', __FILE__); break; } - default: - $return = $_page; - break; } return ucfirst($return); } diff --git a/core/repo/market.repo.php b/core/repo/market.repo.php index 97b7c08c33..66ed0841de 100644 --- a/core/repo/market.repo.php +++ b/core/repo/market.repo.php @@ -370,10 +370,9 @@ public static function backup_list() { 'timestamp' => strtotime($file->propstat->prop->getlastmodified) ); } - function cmp($a,$b){ // $a,$b are reference to first index of array - return strcmp($a["timestamp"], $b["timestamp"]); - } - usort($files, "cmp"); + usort($files, function ($a, $b) { // $a,$b are reference to first index of array + return $a['timestamp'] - $b['timestamp']; + }); $result = array(); foreach ($files as $file) { $result[] = $file['name']; diff --git a/desktop/modal/planHeader.configure.php b/desktop/modal/planHeader.configure.php index 5eed1511d3..d9fe525029 100644 --- a/desktop/modal/planHeader.configure.php +++ b/desktop/modal/planHeader.configure.php @@ -138,6 +138,7 @@ $tr .= $plan->getLink_id(); $tr .= ''; $tr .= '