added custom script plus some debugging
This commit is contained in:
parent
d79463fbd4
commit
5224d00d5a
@ -23,7 +23,7 @@ class availability
|
|||||||
{
|
{
|
||||||
$log = INFO;
|
$log = INFO;
|
||||||
}
|
}
|
||||||
$device->availability = $value
|
$device->availability = $value;
|
||||||
logger($log, sprintf(_("Device: %s/%s is %s"), $topic, $fn , $value));
|
logger($log, sprintf(_("Device: %s/%s is %s"), $topic, $fn , $value));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -32,12 +32,12 @@ class device
|
|||||||
|
|
||||||
public function set($event)
|
public function set($event)
|
||||||
{
|
{
|
||||||
publish($this, $this->payload, "set", $event);
|
publish($this->topic . "/" . $this->friendlyName, $this->payload, "set", $event);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get()
|
public function get()
|
||||||
{
|
{
|
||||||
publish($this, $this->payload, "get", $event);
|
publish($this->topic . "/" . $this->friendlyNames, $this->payload, "get", $event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,10 @@ function searchPropertyKey($fn, &$device, $object, $listPropertiesKeys)
|
|||||||
{
|
{
|
||||||
foreach($object as $key => $value)
|
foreach($object as $key => $value)
|
||||||
{
|
{
|
||||||
|
if (gettype($value) == "object" or gettype($value) == "array")
|
||||||
|
{
|
||||||
|
searchPropertyKey($fn, $device, $value, $listPropertiesKeys);
|
||||||
|
}
|
||||||
if ( isset($value->property))
|
if ( isset($value->property))
|
||||||
{
|
{
|
||||||
//echo "property ===> " . $value->property . EOL;
|
//echo "property ===> " . $value->property . EOL;
|
||||||
@ -116,7 +119,14 @@ function changeDevice($topic, $fn, &$device, $payloadArray)
|
|||||||
{
|
{
|
||||||
//$fnTree = explode("/", $fn);
|
//$fnTree = explode("/", $fn);
|
||||||
//print_r($payloadArray);
|
//print_r($payloadArray);
|
||||||
iterateDevice($topic, $fn, $device, $payloadArray);
|
if (!empty($payloadArray))
|
||||||
|
{
|
||||||
|
iterateDevice($topic, $fn, $device, $payloadArray);
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
logger(ERROR, _("payloadArray is empty!"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterateDevice($topic, $fn, &$device, $payloadArray)
|
function iterateDevice($topic, $fn, &$device, $payloadArray)
|
||||||
@ -173,7 +183,7 @@ function iterateDevice($topic, $fn, &$device, $payloadArray)
|
|||||||
|
|
||||||
if (!empty($device->functions))
|
if (!empty($device->functions))
|
||||||
{
|
{
|
||||||
echo "executing notifications functions " . EOL;
|
//echo "executing notifications functions " . EOL;
|
||||||
foreach($device->functions as $function)
|
foreach($device->functions as $function)
|
||||||
{
|
{
|
||||||
//print_r($function);
|
//print_r($function);
|
||||||
|
16
events.php
16
events.php
@ -30,7 +30,7 @@ function checkEvents()
|
|||||||
if ($exception === false)
|
if ($exception === false)
|
||||||
{
|
{
|
||||||
echo "---->sending command set " . $event->param . "=>" . $event->value . " to " . $event->device->friendlyName . EOL;
|
echo "---->sending command set " . $event->param . "=>" . $event->value . " to " . $event->device->friendlyName . EOL;
|
||||||
publish($event->device, array($event->param => $event->value), "set", $key);
|
publish(mktopic($event->device), array($event->param => $event->value), "set", $key);
|
||||||
if (($event->dateTimeEvent->add($event->recurrenceInterval)) === false)
|
if (($event->dateTimeEvent->add($event->recurrenceInterval)) === false)
|
||||||
{
|
{
|
||||||
logger(ERROR, _("Error in event recurrence. event: ") . $key);
|
logger(ERROR, _("Error in event recurrence. event: ") . $key);
|
||||||
@ -40,7 +40,7 @@ function checkEvents()
|
|||||||
}elseif (!empty($event->dateTimeEvent) and $event->dateTimeEvent <= now())
|
}elseif (!empty($event->dateTimeEvent) and $event->dateTimeEvent <= now())
|
||||||
{
|
{
|
||||||
echo "---->sending command set " . $event->param . "=>" . $event->value . " to " . $event->device->friendlyName . EOL;
|
echo "---->sending command set " . $event->param . "=>" . $event->value . " to " . $event->device->friendlyName . EOL;
|
||||||
$mid = publish($event->device, array($event->param => $event->value), "set", $key);
|
$mid = publish(mktopic($event->device), array($event->param => $event->value), "set", $key);
|
||||||
$event->published = now();
|
$event->published = now();
|
||||||
//echo "#################################\nUnsetting event $key \n###########################" . EOL;
|
//echo "#################################\nUnsetting event $key \n###########################" . EOL;
|
||||||
unset($events[$key]);
|
unset($events[$key]);
|
||||||
@ -168,8 +168,16 @@ function searchEvent($device, $param , $value)
|
|||||||
function deleteEvent($eventKey)
|
function deleteEvent($eventKey)
|
||||||
{
|
{
|
||||||
global $events;
|
global $events;
|
||||||
unset ($events[$eventKey]);
|
if ($eventKey !==false)
|
||||||
logger(INFO, _("delete event ") . $eventKey);
|
{
|
||||||
|
unset ($events[$eventKey]);
|
||||||
|
logger(INFO, _("delete event key =") . $eventKey);
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
//try to delete an flase event
|
||||||
|
logger(WARNING, _("Try to delete event with key = ") . var_dump($eventKey));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,24 +13,32 @@ class notificationFreemobile
|
|||||||
|
|
||||||
function send($message)
|
function send($message)
|
||||||
{
|
{
|
||||||
|
global $curlErr;
|
||||||
|
$result = false;
|
||||||
if ($this->active == true)
|
if ($this->active == true)
|
||||||
{
|
{
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
// set url
|
// set url
|
||||||
curl_setopt($ch, CURLOPT_URL, $this->url . $message);
|
curl_setopt($ch, CURLOPT_URL, $this->url . urlencode(trim($message)));
|
||||||
|
echo $this->url . urlencode(trim($message)) . EOL;
|
||||||
//return the transfer as a string
|
//return the transfer as a string
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
//curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
|
||||||
// $output contains the output string
|
// $result contains the output string
|
||||||
if (($result = curl_exec($ch)) === false)
|
echo "1 curlErr =>"; var_dump($curlErr); echo EOL;
|
||||||
|
if ($curlErr <= 10)
|
||||||
{
|
{
|
||||||
logger(ERROR, _(sprintf( "Curl return error: %s when sending notification", curl_error($ch))));
|
$result = curl_exec($ch);
|
||||||
}else
|
echo "1 result => "; var_dump($result);echo EOL;
|
||||||
{
|
if ($result === false)
|
||||||
logger(INFO, _("Curl return: ") . $result . _(" when sending notification"));
|
{
|
||||||
|
$curlErr += 1;
|
||||||
|
logger(ERROR, sprintf( _("Curl return error %d: %s when sending notification"), curl_errno($ch), curl_error($ch)), false);
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
logger(INFO, sprintf(_("Curl return: %s when sending notification"), $result), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// close curl resource to free up system resources
|
// close curl resource to free up system resources
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
class rdc_panneau_salon
|
class rdc_salon_eclairage
|
||||||
{
|
{
|
||||||
|
public $hookName = "rdc_salon_eclairage";
|
||||||
|
public $active = true;
|
||||||
// list of devices we are listening to
|
// list of devices we are listening to
|
||||||
private $devicelist = array("0x00124b0022ebac5c", "0x588e81fffe2cf695", "0x00124b001f900753", "0x04cf8cdf3c78aff0");
|
private $devicelist = array("0x00124b0022ebac5c", "0x588e81fffe2cf695", "0x00124b001f900753", "0x04cf8cdf3c78aff0");
|
||||||
public $delay = 3; // amount of time in $timeunit
|
public $delay = 3; // amount of time in $timeunit
|
||||||
@ -14,9 +16,12 @@ class rdc_panneau_salon
|
|||||||
global $indexDevices;
|
global $indexDevices;
|
||||||
|
|
||||||
// assigne the function to the sensors devices
|
// assigne the function to the sensors devices
|
||||||
foreach ($this->devicelist as $ieeeAddress)
|
if ($this->active === true)
|
||||||
{
|
{
|
||||||
$indexDevices[$ieeeAddress]->functions[] = array($this,"callback");
|
foreach ($this->devicelist as $ieeeAddress)
|
||||||
|
{
|
||||||
|
$indexDevices[$ieeeAddress]->functions[] = array($this,"callback");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,9 +45,9 @@ class rdc_panneau_salon
|
|||||||
break;
|
break;
|
||||||
case "illuminance_lux":
|
case "illuminance_lux":
|
||||||
if ($value >= $this->luminance_max) $this->send("OFF");
|
if ($value >= $this->luminance_max) $this->send("OFF");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
echo _("notification received from MQTT") . EOL;
|
logger (sprintf(_(INFO, "%s: notification received from MQTT from %s => parameter: %s value: %s"), $hookName, $device["friendlyName"], $param, $value));
|
||||||
//echo $param . "=> " . $value . EOL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function send($state)
|
private function send($state)
|
||||||
@ -50,12 +55,12 @@ class rdc_panneau_salon
|
|||||||
global $devices, $indexDevices;
|
global $devices, $indexDevices;
|
||||||
$msg = array("state" => $state);
|
$msg = array("state" => $state);
|
||||||
$device = & $indexDevices["0x588e81fffe343e8f"];
|
$device = & $indexDevices["0x588e81fffe343e8f"];
|
||||||
logger(INFO, _("publishing ") . $msg . _(" message: ") . $device->friendlyName);
|
logger(INFO, sprintf(_("publishing message: %s to %s"), $msg, $device->friendlyName));
|
||||||
$device->payload = $msg;
|
$device->payload = $msg;
|
||||||
$device->set(null);
|
$device->set(null);
|
||||||
setDelay($device, $this->delay, $this->timeUnit, "state", "OFF", true);
|
setDelay($device, $this->delay, $this->timeUnit, "state", "OFF", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$hooks["rdc/panneau/salon"] = new rdc_panneau_salon();
|
$hooks["rdc_salon_eclairage"] = new rdc_salon_eclairage();
|
||||||
?>
|
?>
|
75
hooks/scripts/rdc_sdb_eclairage.php
Normal file
75
hooks/scripts/rdc_sdb_eclairage.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class rdc_sdb_eclairage
|
||||||
|
{
|
||||||
|
public $hookName = "rdc_sdb_eclairage";
|
||||||
|
public $active = false;
|
||||||
|
|
||||||
|
// list of devices we are listening to
|
||||||
|
// 0x00158d0003f0f3b4 douche mvmnt
|
||||||
|
// 0x842e14fffe1c0cd1 plafond mvmnt
|
||||||
|
// 0x00124b0022ec05dc mvmnt
|
||||||
|
// 0x00158d0005c1a998 module commutateur => state_l1
|
||||||
|
private $devicelist = array("0x00158d0003f0f3b4", "0x842e14fffe1c0cd1", "0x00124b0022ec05dc");
|
||||||
|
|
||||||
|
public $delay = 3; // amount of time in $timeunit
|
||||||
|
public $delayManual = 15; // amount of time in $timeunit for manual mode
|
||||||
|
public $timeUnit = "minute"; // unit of time for delay, second, minute, day, week, month, year
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
global $indexDevices;
|
||||||
|
|
||||||
|
// assigne the function to the sensors devices
|
||||||
|
if ($this->active === true)
|
||||||
|
{
|
||||||
|
foreach ($this->devicelist as $ieeeAddress)
|
||||||
|
{
|
||||||
|
$indexDevices[$ieeeAddress]->functions[] = array($this,"callback");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback fonction. Is called with these 4 parameters
|
||||||
|
public function callBack(&$device, $param, $value)
|
||||||
|
{
|
||||||
|
global $devices, $indexDevices;
|
||||||
|
switch($param)
|
||||||
|
{
|
||||||
|
case "occupancy":
|
||||||
|
if ($value == ON)
|
||||||
|
{
|
||||||
|
$this->send("ON");
|
||||||
|
setDelay($device, $this->delay, $this->timeUnit, "state_l1", "OFF", true);
|
||||||
|
$device->method = AUTO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "state_l1":
|
||||||
|
if ($value == ON)
|
||||||
|
{
|
||||||
|
$this->send("ON");
|
||||||
|
setDelay($device, $this->delayManual, $this->timeUnit, "state_l1", "OFF", true);
|
||||||
|
$device->method = MANUAL;
|
||||||
|
}elseif ($value = OFF)
|
||||||
|
{
|
||||||
|
deleteEvent(searchEvent($device, "state_l1", "OFF"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
logger (INFO, _("%s: notification received from MQTT from %s => parameter: %s value: %s"), $hookName, $device["friendlyName"], $param, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function send($state)
|
||||||
|
{
|
||||||
|
global $devices, $indexDevices;
|
||||||
|
$msg = array("state_l1" => $state);
|
||||||
|
$device = & $indexDevices["0x00158d0005c1a998"];
|
||||||
|
logger(INFO, sprintf(_("publishing message: %s to %s"), $msg, $device->friendlyName));
|
||||||
|
$device->payload = $msg;
|
||||||
|
$device->set(null);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$hooks["rdc-sdb-eclairage"] = new rdc_sdb_eclairage();
|
||||||
|
?>
|
33
moha.php
33
moha.php
@ -3,6 +3,10 @@
|
|||||||
//Constants
|
//Constants
|
||||||
define( "EOL", "\n");
|
define( "EOL", "\n");
|
||||||
define("Z2M", "zigbee2mqtt");
|
define("Z2M", "zigbee2mqtt");
|
||||||
|
define("ON", 1);
|
||||||
|
define("OFF", 0);
|
||||||
|
define("AUTO", 0);
|
||||||
|
define("MANUAL", 1);
|
||||||
|
|
||||||
declare(ticks = 1);
|
declare(ticks = 1);
|
||||||
|
|
||||||
@ -26,6 +30,7 @@ $connected = false; // connected to MQTT server
|
|||||||
$included = false; // flag indicate scripts are loaded
|
$included = false; // flag indicate scripts are loaded
|
||||||
$nSubscribed = 0; // Number of topics subsribed
|
$nSubscribed = 0; // Number of topics subsribed
|
||||||
$logFh = null; // filehandle of log file
|
$logFh = null; // filehandle of log file
|
||||||
|
$curlErr = 0; // Number of errors returned by curl
|
||||||
|
|
||||||
// topics definition
|
// topics definition
|
||||||
$topics["zigbee2mqtt"] = new topic;
|
$topics["zigbee2mqtt"] = new topic;
|
||||||
@ -41,15 +46,16 @@ if (!init()) exit(1);
|
|||||||
$client = new Mosquitto\Client();
|
$client = new Mosquitto\Client();
|
||||||
|
|
||||||
// log levels
|
// log levels
|
||||||
define( "DEBUG", $client::LOG_DEBUG);
|
define( "DEBUG", $client::LOG_DEBUG); // => 16
|
||||||
define( "INFO", $client::LOG_INFO);
|
define( "INFO", $client::LOG_INFO); // => 1
|
||||||
define( "NOTICE", $client::LOG_NOTICE);
|
define( "NOTICE", $client::LOG_NOTICE); // => 2
|
||||||
define( "WARNING", $client::LOG_WARNING);
|
define( "WARNING", $client::LOG_WARNING); // => 4
|
||||||
define( "ERROR", $client::LOG_ERR);
|
define( "ERROR", $client::LOG_ERR); // => 8
|
||||||
define( "ALL", DEBUG | INFO | NOTICE | WARNING | ERROR);
|
define( "ALL", DEBUG | INFO | NOTICE | WARNING | ERROR);
|
||||||
$logLevel = DEBUG;
|
$logLevel = ALL;
|
||||||
$notificationLevel = WARNING | ERROR;
|
$notificationLevel = WARNING | ERROR;
|
||||||
|
|
||||||
|
|
||||||
require "utils.php";
|
require "utils.php";
|
||||||
require "mqtt_functions.php";
|
require "mqtt_functions.php";
|
||||||
require "events.php";
|
require "events.php";
|
||||||
@ -80,7 +86,7 @@ foreach($topics as $name => $topic)
|
|||||||
$mids[$topic->mid] = $name;
|
$mids[$topic->mid] = $name;
|
||||||
$topic->status = false;
|
$topic->status = false;
|
||||||
}
|
}
|
||||||
|
$oneshot = false;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
$client->loop();
|
$client->loop();
|
||||||
@ -99,6 +105,10 @@ while (true)
|
|||||||
}
|
}
|
||||||
}elseif($dbInit == 2 and $included)
|
}elseif($dbInit == 2 and $included)
|
||||||
{
|
{
|
||||||
|
if ($oneshot === false) // execute once initialization finished
|
||||||
|
{
|
||||||
|
$oneshot = true;
|
||||||
|
}
|
||||||
checkEvents();
|
checkEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,14 +161,7 @@ function endMoha()
|
|||||||
{
|
{
|
||||||
global $topics, $nSubscribed ,$client, $logFh, $connected;
|
global $topics, $nSubscribed ,$client, $logFh, $connected;
|
||||||
$x = 0;
|
$x = 0;
|
||||||
/*foreach($topics as $topic => $object)
|
$mid = $client->unsubscribe("#");
|
||||||
{
|
|
||||||
if ($object->status)
|
|
||||||
{*/
|
|
||||||
$mid = $client->unsubscribe("#");
|
|
||||||
/*$mids[$mid] = $topic;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
while ($connected)
|
while ($connected)
|
||||||
{
|
{
|
||||||
|
@ -55,11 +55,12 @@ function message($message)
|
|||||||
foreach($fnTree as $fn)
|
foreach($fnTree as $fn)
|
||||||
{
|
{
|
||||||
//print_r($device) ;
|
//print_r($device) ;
|
||||||
if (!isset($device[$fn]))
|
if (!isset($device[$fn])) //must not exists, but ...
|
||||||
{
|
{
|
||||||
logger(LOG_INFO, $logFh, "init of " . $fn .EOL);
|
logger(LOG_WARNING, $logFh, "init of " . $fn .EOL);
|
||||||
$device[$fn] = array();
|
$device[$fn] = array();
|
||||||
$device[$fn]["device"] = new device;
|
$device[$fn]["device"] = new device;
|
||||||
|
//addDevice($device[$fn], $fn, );
|
||||||
}
|
}
|
||||||
$device = & $device[$fn];
|
$device = & $device[$fn];
|
||||||
}
|
}
|
||||||
@ -69,13 +70,13 @@ function message($message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// payload is an array :
|
// payload is an array :
|
||||||
// key is parameter => value is value of parameter
|
// $key is parameter => $value is value of the parameter
|
||||||
|
|
||||||
function publish($device, $payload, $commande="set", $eventKey)
|
function publish($topic, $payload, $commande="set", $eventKey)
|
||||||
{
|
{
|
||||||
global $client, $mids, $logFh;
|
global $client, $mids, $logFh;
|
||||||
//print_r($payload);
|
//print_r($payload);
|
||||||
$string = $device->topic . "/" . $device->friendlyName . "/" . $commande;
|
$string = $topic . "/" . $commande;
|
||||||
$mid = $client->publish($string, json_encode($payload) , 2);
|
$mid = $client->publish($string, json_encode($payload) , 2);
|
||||||
if (isset($mids[$mid]))
|
if (isset($mids[$mid]))
|
||||||
{
|
{
|
||||||
@ -93,7 +94,7 @@ function publish($device, $payload, $commande="set", $eventKey)
|
|||||||
function connectResponse($r, $message)
|
function connectResponse($r, $message)
|
||||||
{
|
{
|
||||||
global $connected;
|
global $connected;
|
||||||
echo _("I got code ") . $r . _(" and message : '") . $message . "'" . EOL;
|
echo sprintf(_("I got code %d and message : '%s'"), $r, $message) . EOL;
|
||||||
switch ($r)
|
switch ($r)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
22
utils.php
22
utils.php
@ -16,27 +16,35 @@ function notify($message)
|
|||||||
$result = false;
|
$result = false;
|
||||||
foreach($notificationMethods as $value)
|
foreach($notificationMethods as $value)
|
||||||
{
|
{
|
||||||
$result |= $value->send($message);
|
$result = $result | $value->send($message);
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function logger($level, $log)
|
function logger($level, $log, $notif = true)
|
||||||
{
|
{
|
||||||
global $logFh, $logLevel, $notificationLevel;
|
global $logFh, $logLevel, $notificationLevel;
|
||||||
echo "$level"
|
echo "=====>>>> $level => $logLevel => $notificationLevel" . EOL ;
|
||||||
if ( $level >= $logLevel)
|
echo $log .EOL;
|
||||||
|
$test = $level & $logLevel;
|
||||||
|
if ($test != 0)
|
||||||
{
|
{
|
||||||
fwrite($logFh, "$level : $log" . EOL);
|
fwrite($logFh, "$level : $log" . EOL);
|
||||||
print ("$level : $log" . EOL);
|
print ("$level : $log" . EOL);
|
||||||
}
|
}
|
||||||
if ($level >= $notificationLevel)
|
$test = $level & $notificationLevel;
|
||||||
|
echo "test => " . $test . "notif =>" .$notif . EOL;
|
||||||
|
if (($test != 0) and ($notif === true))
|
||||||
{
|
{
|
||||||
if(notify(" Moha\n" . $log) == false)
|
if(notify("Moha\n" . $log) === false)
|
||||||
{
|
{
|
||||||
logger(INFO, _("Notification not sent"));
|
logger(INFO, _("Notification not sent"), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mktopic($device)
|
||||||
|
{
|
||||||
|
return $device->topic . "/" . $device->friendlyName;
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
Loading…
Reference in New Issue
Block a user