adapt to 4.1.x
This commit is contained in:
parent
af2f10bde8
commit
630620edbd
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.openhab.addons.bundles</groupId>
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>4.1.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>org.openhab.binding.mediolaaiogateway</artifactId>
|
<artifactId>org.openhab.binding.mediolaaiogateway</artifactId>
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mediolaaiogateway.internal.config;
|
package org.openhab.binding.mediolaaiogateway.internal.config;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MediolaAioBridgeConfig} class contains fields mapping thing configuration parameters.
|
* The {@link MediolaAioBridgeConfig} class contains fields mapping thing configuration parameters.
|
||||||
*
|
*
|
||||||
|
|
|
@ -12,8 +12,12 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mediolaaiogateway.internal.discovery;
|
package org.openhab.binding.mediolaaiogateway.internal.discovery;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import static org.openhab.binding.mediolaaiogateway.internal.MediolaAioGatewayBindingConstants.THING_TYPE_ELERO_DEVICE;
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.mediolaaiogateway.internal.exception.MediolaAioCommandError;
|
import org.openhab.binding.mediolaaiogateway.internal.exception.MediolaAioCommandError;
|
||||||
|
@ -30,11 +34,8 @@ import org.openhab.core.thing.binding.ThingHandlerService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import com.google.gson.JsonElement;
|
||||||
import java.util.Map;
|
import com.google.gson.JsonObject;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.openhab.binding.mediolaaiogateway.internal.MediolaAioGatewayBindingConstants.THING_TYPE_ELERO_DEVICE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MediolaAioDeviceDiscoveryService} is used to discover devices that are connected to a Homematic gateway.
|
* The {@link MediolaAioDeviceDiscoveryService} is used to discover devices that are connected to a Homematic gateway.
|
||||||
|
@ -42,15 +43,11 @@ import static org.openhab.binding.mediolaaiogateway.internal.MediolaAioGatewayBi
|
||||||
* @author Gerhard Riegler - Initial contribution
|
* @author Gerhard Riegler - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class MediolaAioDeviceDiscoveryService extends AbstractDiscoveryService
|
public class MediolaAioDeviceDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
|
||||||
implements ThingHandlerService {
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(MediolaAioDeviceDiscoveryService.class);
|
private final Logger logger = LoggerFactory.getLogger(MediolaAioDeviceDiscoveryService.class);
|
||||||
private static final int DISCOVER_TIMEOUT_SECONDS = 300;
|
private static final int DISCOVER_TIMEOUT_SECONDS = 300;
|
||||||
|
|
||||||
private @NonNullByDefault({})
|
private @NonNullByDefault({}) MediolaAioGatewayBridgeHandler bridgeHandler;
|
||||||
MediolaAioGatewayBridgeHandler bridgeHandler;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public MediolaAioDeviceDiscoveryService() {
|
public MediolaAioDeviceDiscoveryService() {
|
||||||
super(Set.of(THING_TYPE_ELERO_DEVICE), DISCOVER_TIMEOUT_SECONDS, false);
|
super(Set.of(THING_TYPE_ELERO_DEVICE), DISCOVER_TIMEOUT_SECONDS, false);
|
||||||
|
@ -95,14 +92,13 @@ public class MediolaAioDeviceDiscoveryService extends AbstractDiscoveryService
|
||||||
|
|
||||||
String strAddress = String.format("%02X", address);
|
String strAddress = String.format("%02X", address);
|
||||||
|
|
||||||
ThingUID thingUID = new ThingUID(THING_TYPE_ELERO_DEVICE, bridgeHandler.getThing().getUID(), strAddress);
|
ThingUID thingUID = new ThingUID(THING_TYPE_ELERO_DEVICE, bridgeHandler.getThing().getUID(),
|
||||||
|
strAddress);
|
||||||
|
|
||||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
||||||
.withBridge(bridgeHandler.getThing().getUID())
|
.withBridge(bridgeHandler.getThing().getUID())
|
||||||
.withLabel(String.format("Elero Device %s", strAddress))
|
.withLabel(String.format("Elero Device %s", strAddress))
|
||||||
.withProperty("deviceAddress", address)
|
.withProperty("deviceAddress", address).withProperty("deviceSid", sid).build();
|
||||||
.withProperty("deviceSid", sid)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
thingDiscovered(discoveryResult);
|
thingDiscovered(discoveryResult);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,11 @@ package org.openhab.binding.mediolaaiogateway.internal.handler;
|
||||||
|
|
||||||
import static org.openhab.binding.mediolaaiogateway.internal.MediolaAioGatewayBindingConstants.*;
|
import static org.openhab.binding.mediolaaiogateway.internal.MediolaAioGatewayBindingConstants.*;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
@ -32,10 +36,7 @@ import org.openhab.core.types.RefreshType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import com.google.gson.JsonElement;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MediolaAioEleroDeviceHandler} is responsible for handling commands, which are
|
* The {@link MediolaAioEleroDeviceHandler} is responsible for handling commands, which are
|
||||||
|
@ -46,7 +47,6 @@ import java.util.concurrent.TimeUnit;
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class MediolaAioEleroDeviceHandler extends BaseThingHandler {
|
public class MediolaAioEleroDeviceHandler extends BaseThingHandler {
|
||||||
|
|
||||||
|
|
||||||
private static final Map<String, Integer> _commandMap = new HashMap<>();
|
private static final Map<String, Integer> _commandMap = new HashMap<>();
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(MediolaAioEleroDeviceHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(MediolaAioEleroDeviceHandler.class);
|
||||||
|
@ -82,14 +82,18 @@ public class MediolaAioEleroDeviceHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stateUpdate(ChannelUID channelUID) {
|
public void stateUpdate(ChannelUID channelUID) {
|
||||||
@Nullable Bridge bridge = getBridge();
|
@Nullable
|
||||||
|
Bridge bridge = getBridge();
|
||||||
if (bridge == null) {
|
if (bridge == null) {
|
||||||
logger.warn("could not get bridge");
|
logger.warn("could not get bridge");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@Nullable MediolaAioGatewayBridgeHandler bHandler = (MediolaAioGatewayBridgeHandler) bridge.getHandler();
|
@Nullable
|
||||||
|
MediolaAioGatewayBridgeHandler bHandler = (MediolaAioGatewayBridgeHandler) bridge.getHandler();
|
||||||
|
|
||||||
if ( bHandler == null || config == null) { return; }
|
if (bHandler == null || config == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, String> params = new HashMap<>();
|
Map<String, String> params = new HashMap<>();
|
||||||
params.put("adr", String.format("%02x", config.deviceAddress));
|
params.put("adr", String.format("%02x", config.deviceAddress));
|
||||||
|
@ -107,10 +111,14 @@ public class MediolaAioEleroDeviceHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCommandString(String cmd) {
|
private void handleCommandString(String cmd) {
|
||||||
@Nullable Bridge bridge = getBridge();
|
@Nullable
|
||||||
@Nullable MediolaAioGatewayBridgeHandler bHandler = (MediolaAioGatewayBridgeHandler) bridge.getHandler();
|
Bridge bridge = getBridge();
|
||||||
|
@Nullable
|
||||||
|
MediolaAioGatewayBridgeHandler bHandler = (MediolaAioGatewayBridgeHandler) bridge.getHandler();
|
||||||
|
|
||||||
if ( bHandler == null || config == null) { return; }
|
if (bHandler == null || config == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Integer eleroCmd = _commandMap.get(cmd);
|
Integer eleroCmd = _commandMap.get(cmd);
|
||||||
if (eleroCmd != null) {
|
if (eleroCmd != null) {
|
||||||
|
@ -120,9 +128,7 @@ public class MediolaAioEleroDeviceHandler extends BaseThingHandler {
|
||||||
logger.error("Command not successful: {}", mediolaAioCommandError.getMessage());
|
logger.error("Command not successful: {}", mediolaAioCommandError.getMessage());
|
||||||
|
|
||||||
} catch (MediolaAioCommunicationError mediolaAioCommunicationError) {
|
} catch (MediolaAioCommunicationError mediolaAioCommunicationError) {
|
||||||
updateStatus(
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
ThingStatus.OFFLINE,
|
|
||||||
ThingStatusDetail.COMMUNICATION_ERROR,
|
|
||||||
String.format("Could not reach Mediola AIO Gateway"));
|
String.format("Could not reach Mediola AIO Gateway"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,11 +148,9 @@ public class MediolaAioEleroDeviceHandler extends BaseThingHandler {
|
||||||
else if (CHANNEL_CONTROL_BLIND.equals(id)) {
|
else if (CHANNEL_CONTROL_BLIND.equals(id)) {
|
||||||
if (command instanceof UpDownType) {
|
if (command instanceof UpDownType) {
|
||||||
handleCommandString(((UpDownType) command).toString());
|
handleCommandString(((UpDownType) command).toString());
|
||||||
}
|
} else if (command instanceof StopMoveType) {
|
||||||
else if (command instanceof StopMoveType) {
|
|
||||||
handleCommandString(((StopMoveType) command).toString());
|
handleCommandString(((StopMoveType) command).toString());
|
||||||
}
|
} else if (command instanceof PercentType) {
|
||||||
else if (command instanceof PercentType) {
|
|
||||||
int val = ((PercentType) command).intValue();
|
int val = ((PercentType) command).intValue();
|
||||||
if (val == 0) {
|
if (val == 0) {
|
||||||
// open position
|
// open position
|
||||||
|
@ -212,8 +216,11 @@ public class MediolaAioEleroDeviceHandler extends BaseThingHandler {
|
||||||
updateStatus(ThingStatus.UNKNOWN);
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
|
|
||||||
pollingJob = scheduler.scheduleWithFixedDelay(() -> {
|
pollingJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||||
@Nullable Channel ch = thing.getChannel(CHANNEL_STATE);
|
@Nullable
|
||||||
if ( ch == null ) {return; }
|
Channel ch = thing.getChannel(CHANNEL_STATE);
|
||||||
|
if (ch == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.stateUpdate(ch.getUID());
|
this.stateUpdate(ch.getUID());
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,16 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mediolaaiogateway.internal.handler;
|
package org.openhab.binding.mediolaaiogateway.internal.handler;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import java.util.Collection;
|
||||||
import com.google.gson.JsonElement;
|
import java.util.Collections;
|
||||||
import com.google.gson.JsonObject;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import javax.ws.rs.HttpMethod;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
@ -37,14 +44,9 @@ import org.openhab.core.types.Command;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.ws.rs.HttpMethod;
|
import com.google.gson.Gson;
|
||||||
import java.util.Collection;
|
import com.google.gson.JsonElement;
|
||||||
import java.util.Collections;
|
import com.google.gson.JsonObject;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MediolaAioGatewayBridgeHandler} is responsible for handling commands, which are
|
* The {@link MediolaAioGatewayBridgeHandler} is responsible for handling commands, which are
|
||||||
|
@ -75,27 +77,25 @@ public class MediolaAioGatewayBridgeHandler extends BaseBridgeHandler {
|
||||||
return Collections.singleton(MediolaAioDeviceDiscoveryService.class);
|
return Collections.singleton(MediolaAioDeviceDiscoveryService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonElement sendEleroCommand(Integer deviceAddress, Integer cmd) throws MediolaAioCommandError, MediolaAioCommunicationError {
|
public JsonElement sendEleroCommand(Integer deviceAddress, Integer cmd)
|
||||||
|
throws MediolaAioCommandError, MediolaAioCommunicationError {
|
||||||
Map<String, String> params = new HashMap<>();
|
Map<String, String> params = new HashMap<>();
|
||||||
params.put("type", AioType.Elero);
|
params.put("type", AioType.Elero);
|
||||||
params.put("data", String.format("%02x%02x", deviceAddress, cmd));
|
params.put("data", String.format("%02x%02x", deviceAddress, cmd));
|
||||||
return this.sendCommand(AioCommand.SendSC, params);
|
return this.sendCommand(AioCommand.SendSC, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonElement sendCommand(String command, Map<String, String> params) throws MediolaAioCommandError, MediolaAioCommunicationError {
|
public JsonElement sendCommand(String command, Map<String, String> params)
|
||||||
|
throws MediolaAioCommandError, MediolaAioCommunicationError {
|
||||||
|
|
||||||
Request request = _httpClient.newRequest(config.gatewayAddress, config.gatewayPort)
|
Request request = _httpClient.newRequest(config.gatewayAddress, config.gatewayPort).scheme("http")
|
||||||
.scheme("http")
|
.agent("OpenHAB Mediola AIO Gateway Binding").version(HttpVersion.HTTP_1_1).method(HttpMethod.GET)
|
||||||
.agent("OpenHAB Mediola AIO Gateway Binding")
|
.path("/cmd").param("XC_FNC", command).timeout(5, TimeUnit.SECONDS);
|
||||||
.version(HttpVersion.HTTP_1_1)
|
|
||||||
.method(HttpMethod.GET)
|
|
||||||
.path("/cmd")
|
|
||||||
.param("XC_FNC", command)
|
|
||||||
.timeout(5, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
params.forEach(request::param);
|
params.forEach(request::param);
|
||||||
|
|
||||||
@Nullable ContentResponse response;
|
@Nullable
|
||||||
|
ContentResponse response;
|
||||||
byte[] content;
|
byte[] content;
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
@ -127,7 +127,6 @@ public class MediolaAioGatewayBridgeHandler extends BaseBridgeHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
config = getConfigAs(MediolaAioBridgeConfig.class);
|
config = getConfigAs(MediolaAioBridgeConfig.class);
|
||||||
|
|
|
@ -47,7 +47,8 @@ public class MediolaAioGatewayHandlerFactory extends BaseThingHandlerFactory {
|
||||||
httpClient = httpClientFactory.getCommonHttpClient();
|
httpClient = httpClientFactory.getCommonHttpClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_BRIDGE, THING_TYPE_ELERO_DEVICE);
|
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_BRIDGE,
|
||||||
|
THING_TYPE_ELERO_DEVICE);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mediolaaiogateway.internal.mediolaapi;
|
package org.openhab.binding.mediolaaiogateway.internal.mediolaapi;
|
||||||
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,5 +38,4 @@ public class AioEleroCommand {
|
||||||
public static final Integer ASMove = 0x10;
|
public static final Integer ASMove = 0x10;
|
||||||
public static final Integer SaveVentilationPos = 0x14;
|
public static final Integer SaveVentilationPos = 0x14;
|
||||||
public static final Integer SaveIntermediatePos = 0x12;
|
public static final Integer SaveIntermediatePos = 0x12;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mediolaaiogateway.internal.mediolaapi;
|
package org.openhab.binding.mediolaaiogateway.internal.mediolaapi;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<thing:thing-descriptions bindingId="mediolaaiogateway" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<thing:thing-descriptions bindingId="mediolaaiogateway"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<thing:thing-descriptions bindingId="mediolaaiogateway" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<thing:thing-descriptions bindingId="mediolaaiogateway"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue