Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.gridsuite.network.map.dto.definition.extension;

import com.fasterxml.jackson.annotation.JsonInclude;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright (c) 2025, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.gridsuite.network.map.dto.definition.voltagelevel;

import org.gridsuite.network.map.dto.definition.extension.ConnectablePositionInfos;

/**
* @author Etienne Lesot <etienne.lesot at rte-france.com>
*/
public record FeederBayInfos(String busbarId, ConnectablePositionInfos connectablePositionInfos, Integer side) { }
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,7 @@ public class VoltageLevelFormInfos extends ElementInfosWithProperties {

@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, List<String>> busBarSectionInfos;

@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, List<FeederBayInfos>> feederBaysInfos;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.gridsuite.network.map.dto.ElementInfos;
import org.gridsuite.network.map.dto.InfoTypeParameters;
import org.gridsuite.network.map.dto.definition.busbarsection.BusBarSectionFormInfos;
import org.gridsuite.network.map.dto.definition.voltagelevel.FeederBayInfos;
import org.gridsuite.network.map.dto.definition.voltagelevel.VoltageLevelFormInfos;
import org.gridsuite.network.map.dto.definition.voltagelevel.VoltageLevelMapInfos;
import org.gridsuite.network.map.dto.definition.voltagelevel.VoltageLevelTabInfos;
Expand Down Expand Up @@ -106,14 +107,39 @@ static VoltageLevelFormInfos toFormInfos(Identifiable<?> identifiable) {
builder.isRetrievedBusbarSections(vlTopologyInfos.isRetrievedBusbarSections());
builder.isBusbarSectionPositionFound(vlTopologyInfos.isBusbarSectionPositionFound());
builder.busBarSectionInfos(vlTopologyInfos.getBusBarSectionInfosGrouped());
builder.feederBaysInfos(getConnectionInfos(voltageLevel));
}

builder.identifiableShortCircuit(ExtensionUtils.toIdentifiableShortCircuit(voltageLevel));

return builder.build();
}

static VoltageLevelMapInfos toMapInfos(Identifiable<?> identifiable) {
private static Map<String, List<FeederBayInfos>> getConnectionInfos(VoltageLevel voltageLevel) {
Map<String, List<FeederBayInfos>> connections = new HashMap<>();
voltageLevel.getConnectableStream()
.filter(connectable -> !(connectable instanceof BusbarSection))
.forEach(connectable -> {
switch (connectable) {
case Injection<?> injection -> connections.put(injection.getId(), List.of(new FeederBayInfos(getBusOrBusbarSection(injection.getTerminal()),
toMapConnectablePosition(injection, 0), null)));
case Branch<?> branch -> {
List<FeederBayInfos> branchConnections = new ArrayList<>();
if (branch.getTerminal1().getVoltageLevel().getId().equals(voltageLevel.getId())) {
branchConnections.add(new FeederBayInfos(getBusOrBusbarSection(branch.getTerminal1()), toMapConnectablePosition(branch, 1), 1));
}
if (branch.getTerminal2().getVoltageLevel().getId().equals(voltageLevel.getId())) {
branchConnections.add(new FeederBayInfos(getBusOrBusbarSection(branch.getTerminal2()), toMapConnectablePosition(branch, 2), 2));
}
connections.put(branch.getId(), branchConnections);
}
default -> throw new IllegalArgumentException("connectable type: " + connectable.getClass() + " not supported");
}
});
return connections;
}

protected static VoltageLevelMapInfos toMapInfos(Identifiable<?> identifiable) {
VoltageLevel voltageLevel = (VoltageLevel) identifiable;
return VoltageLevelMapInfos.builder()
.id(voltageLevel.getId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
package org.gridsuite.network.map.dto.utils;

import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.ConnectablePosition;
import com.powsybl.math.graph.TraversalType;
import lombok.NonNull;
import org.gridsuite.network.map.dto.common.ReactiveCapabilityCurveMapData;
import org.gridsuite.network.map.dto.common.TapChangerData;
import org.gridsuite.network.map.dto.common.TapChangerStepData;
import org.gridsuite.network.map.dto.definition.extension.BusbarSectionFinderTraverser;
import org.springframework.lang.NonNull;
import org.gridsuite.network.map.dto.definition.extension.ConnectablePositionInfos;

import java.util.Collection;
import java.util.List;
Expand All @@ -39,6 +41,39 @@ public static void setIfNotNan(@NonNull final DoubleConsumer setter, final doubl
}
}

private static ConnectablePosition.Feeder getFeederInfos(Identifiable<?> identifiable, int index) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code should use ThreeSides

Suggested change
private static ConnectablePosition.Feeder getFeederInfos(Identifiable<?> identifiable, int index) {
private static ConnectablePosition.Feeder getFeederInfos(Identifiable<?> identifiable, ThreeSides side) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the index we can handle injections and branches, but the ThreeSides type cannot manage that

var connectablePosition = identifiable.getExtension(ConnectablePosition.class);
if (connectablePosition == null) {
return null;
}

switch (index) {
case 0:
return connectablePosition.getFeeder();
case 1:
return connectablePosition.getFeeder1();
case 2:
return connectablePosition.getFeeder2();
default:
throw new IllegalArgumentException("Invalid feeder index: " + index);
}
}

public static ConnectablePositionInfos toMapConnectablePosition(Identifiable<?> identifiable, int index) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public static ConnectablePositionInfos toMapConnectablePosition(Identifiable<?> identifiable, int index) {
public static ConnectablePositionInfos getConnectablePosition(Identifiable<?> identifiable, ThreeSides side) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the renaming, but not with changing int index to ThreeSides side, because we need to specify the index to retrieve the feeder

ConnectablePosition.Feeder feeder = getFeederInfos(identifiable, index);
return convertFeederToConnectablePositionInfos(feeder);
}

public static ConnectablePositionInfos convertFeederToConnectablePositionInfos(ConnectablePosition.Feeder feeder) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public static ConnectablePositionInfos convertFeederToConnectablePositionInfos(ConnectablePosition.Feeder feeder) {
public static ConnectablePositionInfos buildConnectablePositionInfos(ConnectablePosition.Feeder feeder) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

ConnectablePositionInfos.ConnectablePositionInfosBuilder builder = ConnectablePositionInfos.builder();
if (feeder != null) {
builder.connectionDirection(feeder.getDirection() == null ? null : feeder.getDirection())
.connectionPosition(feeder.getOrder().orElse(null))
.connectionName(feeder.getName().orElse(null));
}
return builder.build();
}

public static String getBusOrBusbarSection(Terminal terminal) {
if (terminal.getVoltageLevel().getTopologyKind().equals(TopologyKind.BUS_BREAKER)) {
if (terminal.isConnected()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import com.powsybl.network.store.iidm.impl.NetworkFactoryImpl;
import org.gridsuite.network.map.dto.ElementInfos.InfoType;
import org.gridsuite.network.map.dto.ElementType;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
Expand Down Expand Up @@ -1154,6 +1154,48 @@ void setUp() {
.withDirection(ConnectablePosition.Direction.TOP).add()
.add();

// add line between vlgen4 et vlgen 5 for feederBays Infos
VoltageLevel vlgen7 = p5.newVoltageLevel()
.setId("VLGEN7")
.setNominalV(24.0)
.setHighVoltageLimit(30)
.setLowVoltageLimit(20)
.setTopologyKind(TopologyKind.NODE_BREAKER)
.add();
vlgen7.getNodeBreakerView().newBusbarSection()
.setId("NGEN7")
.setName("NGEN7")
.setNode(0)
.add();
createSwitch(vlgen4, "b4", SwitchKind.DISCONNECTOR, false, 0, 10);
createSwitch(vlgen4, "br11", SwitchKind.BREAKER, false, 10, 11);
createSwitch(vlgen7, "b5", SwitchKind.DISCONNECTOR, false, 0, 1);
createSwitch(vlgen7, "br21", SwitchKind.BREAKER, false, 1, 2);
network.newLine()
.setId("LINE7")
.setVoltageLevel1("VLGEN4")
.setNode1(11)
.setVoltageLevel2("VLGEN7")
.setNode2(2)
.setR(3.0)
.setX(33.0)
.setG1(0.0)
.setB1(386E-6 / 2)
.setG2(0.0)
.setB2(386E-6 / 2)
.add();
Line line7 = network.getLine("LINE7");
line7.newExtension(ConnectablePositionAdder.class)
.newFeeder1()
.withName("LINE7_Side_VLGEN4")
.withOrder(5)
.withDirection(ConnectablePosition.Direction.BOTTOM).add()
.newFeeder2()
.withName("LINE7_Side_VLGEN8")
.withOrder(3)
.withDirection(ConnectablePosition.Direction.TOP).add()
.add();

// Add new variant
network.getVariantManager().cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, VARIANT_ID);
network.getVariantManager().setWorkingVariant(VARIANT_ID);
Expand Down Expand Up @@ -1184,7 +1226,6 @@ void setUp() {
.withOrder(0)
.withDirection(ConnectablePosition.Direction.TOP).add()
.add();

network.getVariantManager().setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID);

// Add new variant 2
Expand Down Expand Up @@ -1380,7 +1421,6 @@ private void succeedingTestForElementInfosWithElementId(UUID networkUuid, String
)
.andExpect(status().isOk())
.andReturn();

JSONAssert.assertEquals(expectedJson, res.getResponse().getContentAsString(), JSONCompareMode.NON_EXTENSIBLE);
}

Expand Down Expand Up @@ -1440,7 +1480,6 @@ private void succeedingTestForElementsInfos(UUID networkUuid, String variantId,
)
.andExpect(status().isOk())
.andReturn();

JSONAssert.assertEquals(expectedJson, mvcResult.getResponse().getContentAsString(), JSONCompareMode.NON_EXTENSIBLE);
}

Expand Down Expand Up @@ -1514,7 +1553,6 @@ private void succeedingTestForEquipmentsInfos(UUID networkUuid, String variantId
MvcResult mvcResult = mvc.perform(get("/v1/networks/{networkUuid}/{equipmentPath}", networkUuid, equipmentPath).queryParams(queryParams))
.andExpect(status().isOk())
.andReturn();

JSONAssert.assertEquals(expectedJson, mvcResult.getResponse().getContentAsString(), JSONCompareMode.NON_EXTENSIBLE);
}

Expand Down Expand Up @@ -1681,10 +1719,10 @@ void shouldReturnLinesOperatingStatusData() throws Exception {

@Test
void shouldReturnLinesIds() throws Exception {
succeedingTestForElementsIds(NETWORK_UUID, null, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3", "LINE4").toString(), ElementType.LINE, null, null);
succeedingTestForElementsIds(NETWORK_UUID, null, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3", "LINE4").toString(), ElementType.LINE, null, List.of(24.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3", "LINE4").toString(), ElementType.LINE, null, null);
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3", "LINE4").toString(), ElementType.LINE, null, List.of(24.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, null, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3", "LINE4", "LINE7").toString(), ElementType.LINE, null, null);
succeedingTestForElementsIds(NETWORK_UUID, null, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3", "LINE4", "LINE7").toString(), ElementType.LINE, null, List.of(24.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3", "LINE4", "LINE7").toString(), ElementType.LINE, null, null);
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3", "LINE4", "LINE7").toString(), ElementType.LINE, null, List.of(24.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3").toString(), ElementType.LINE, List.of("P1"), null);
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("NHV1_NHV2_1", "NHV1_NHV2_2", "LINE3").toString(), ElementType.LINE, List.of("P1"), List.of(24.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of().toString(), ElementType.LINE, List.of("P1"), List.of(225.0));
Expand Down Expand Up @@ -2198,12 +2236,12 @@ void shouldReturnVotlageLevelsMapData() throws Exception {

@Test
void shouldReturnVoltageLevelsIds() throws Exception {
succeedingTestForElementsIds(NETWORK_UUID, null, List.of("VL", "VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6").toString(), ElementType.VOLTAGE_LEVEL, null, null);
succeedingTestForElementsIds(NETWORK_UUID, null, List.of("VL", "VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6").toString(), ElementType.VOLTAGE_LEVEL, null, List.of(24.0, 150.0, 225.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("VL", "VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6").toString(), ElementType.VOLTAGE_LEVEL, null, null);
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("VL", "VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6").toString(), ElementType.VOLTAGE_LEVEL, null, List.of(24.0, 150.0, 225.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6").toString(), ElementType.VOLTAGE_LEVEL, List.of("P1", "P2", "P3", "P4", "P5", "P6"), null);
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6").toString(), ElementType.VOLTAGE_LEVEL, List.of("P1", "P2", "P3", "P4", "P5", "P6"), List.of(24.0, 150.0, 225.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, null, List.of("VL", "VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6", "VLGEN7").toString(), ElementType.VOLTAGE_LEVEL, null, null);
succeedingTestForElementsIds(NETWORK_UUID, null, List.of("VL", "VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6", "VLGEN7").toString(), ElementType.VOLTAGE_LEVEL, null, List.of(24.0, 150.0, 225.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("VL", "VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6", "VLGEN7").toString(), ElementType.VOLTAGE_LEVEL, null, null);
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("VL", "VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6", "VLGEN7").toString(), ElementType.VOLTAGE_LEVEL, null, List.of(24.0, 150.0, 225.0, 380.0));
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6", "VLGEN7").toString(), ElementType.VOLTAGE_LEVEL, List.of("P1", "P2", "P3", "P4", "P5", "P6"), null);
succeedingTestForElementsIds(NETWORK_UUID, VARIANT_ID, List.of("VLGEN", "VLHV1", "VLHV2", "VLLOAD", "VLNEW2", "VLGEN3", "VLGEN4", "VLGEN5", "VLGEN6", "VLGEN7").toString(), ElementType.VOLTAGE_LEVEL, List.of("P1", "P2", "P3", "P4", "P5", "P6"), List.of(24.0, 150.0, 225.0, 380.0));
}

@Test
Expand All @@ -2221,11 +2259,16 @@ void shouldReturnNotFoundInsteadOfVoltageLevelsMapData() throws Exception {
}

@Test
void shouldReturnVotlageLevelFormData() throws Exception {
void shouldReturnVoltageLevelFormData() throws Exception {
succeedingTestForElementInfosWithElementId(NETWORK_UUID, null, ElementType.VOLTAGE_LEVEL, InfoType.FORM, "VLGEN4", resourceToString("/voltage-level-form-data.json"));
succeedingTestForElementInfosWithElementId(NETWORK_UUID, VARIANT_ID, ElementType.VOLTAGE_LEVEL, InfoType.FORM, "VLGEN4", resourceToString("/voltage-level-form-data.json"));
}

@Test
void shouldReturnVoltageLevelFormDataWithFeederBaysInfos() throws Exception {
succeedingTestForElementInfosWithElementId(NETWORK_UUID, null, ElementType.VOLTAGE_LEVEL, InfoType.FORM, "VLGEN5", resourceToString("/voltage-level-form-data-feederbays.json"));
}

@Test
void shouldReturnVotlageLevelNonSymmetricalBusbarsFormData() throws Exception {
succeedingTestForElementInfosWithElementId(NETWORK_UUID, null, ElementType.VOLTAGE_LEVEL, InfoType.FORM, "VLGEN5", resourceToString("/voltage-level-non-symmetrical-busbars-form-data.json"));
Expand Down
77 changes: 77 additions & 0 deletions src/test/resources/all-data-in-variant.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@
{
"id": "P5",
"voltageLevels": [
{
"id": "VLGEN7",
"substationId": "P5",
"nominalV": 24.0,
"country": "FR",
"lowVoltageLimit": 20.0,
"highVoltageLimit": 30.0
},
{
"id": "VLGEN5",
"substationId": "P5",
Expand Down Expand Up @@ -219,6 +227,14 @@
"ipMin": 0.0,
"ipMax": 100.0
}
},
{
"id": "VLGEN7",
"substationId": "P5",
"nominalV": 24.0,
"country": "FR",
"lowVoltageLimit": 20.0,
"highVoltageLimit": 30.0
}
],
"lines": [
Expand Down Expand Up @@ -502,6 +518,26 @@
"b1": 1.93E-4,
"g2": 0.0,
"b2": 1.93E-4
},
{
"id": "LINE7",
"type": "LINE",
"voltageLevelId1": "VLGEN4",
"voltageLevelId2": "VLGEN7",
"nominalVoltage1": 24.0,
"nominalVoltage2": 24.0,
"substationId1": "P4",
"substationId2": "P5",
"country1": "FR",
"country2": "FR",
"terminal1Connected": true,
"terminal2Connected": true,
"r": 3.0,
"x": 33.0,
"g1": 0.0,
"b1": 1.93E-4,
"g2": 0.0,
"b2": 1.93E-4
}
],
"hvdcLines": [
Expand Down Expand Up @@ -2345,6 +2381,26 @@
"voltageLevelId": "VLGEN6",
"nominalVoltage": 24.0,
"country": "FR"
},
{
"id": "VLGEN4_0",
"v": "NaN",
"angle": "NaN",
"synchronousComponentNum": 1,
"connectedComponentNum": 1,
"voltageLevelId": "VLGEN4",
"nominalVoltage": 24.0,
"country": "FR"
},
{
"id": "VLGEN7_0",
"v": "NaN",
"angle": "NaN",
"synchronousComponentNum": 1,
"connectedComponentNum": 1,
"voltageLevelId": "VLGEN7",
"nominalVoltage": 24.0,
"country": "FR"
}
],
"busbarSections": [
Expand Down Expand Up @@ -2375,6 +2431,11 @@
"id": "NGEN5_2_2",
"name": "NGEN5_2_2",
"voltageLevelId": "VLGEN5"
},
{
"id": "NGEN7",
"name": "NGEN7",
"voltageLevelId": "VLGEN7"
}
],
"branches": [
Expand Down Expand Up @@ -2643,6 +2704,22 @@
"Country": "FR"
}
},
{
"id": "LINE7",
"type": "LINE",
"voltageLevelId1": "VLGEN4",
"voltageLevelId2": "VLGEN7",
"nominalVoltage1": 24.0,
"nominalVoltage2": 24.0,
"substationId1": "P4",
"substationId2": "P5",
"country1": "FR",
"country2": "FR",
"terminal1Connected": true,
"terminal2Connected": true,
"r": 3.0,
"x": 33.0
},
{
"id": "NGEN_NHV1",
"type": "TWO_WINDINGS_TRANSFORMER",
Expand Down
Loading