implement complete missions
This commit is contained in:
@@ -159,12 +159,18 @@ public class HelperController {
|
|||||||
this.route.currentEntryProperty().removeListener(currentEntryListener);
|
this.route.currentEntryProperty().removeListener(currentEntryListener);
|
||||||
}
|
}
|
||||||
this.route = route;
|
this.route = route;
|
||||||
|
if (route != null) {
|
||||||
setRouteEntry(route.getCurrentEntry());
|
setRouteEntry(route.getCurrentEntry());
|
||||||
this.route.currentEntryProperty().addListener(currentEntryListener);
|
this.route.currentEntryProperty().addListener(currentEntryListener);
|
||||||
showStationInfo();
|
showStationInfo();
|
||||||
|
} else {
|
||||||
|
setRouteEntry(-1);
|
||||||
|
hideStationInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setRouteEntry(int index){
|
private void setRouteEntry(int index){
|
||||||
|
if (index != -1) {
|
||||||
entry = route.get(index);
|
entry = route.get(index);
|
||||||
station.setText(entry.getStation().getName());
|
station.setText(entry.getStation().getName());
|
||||||
system.setText(entry.getStation().getSystem().getName());
|
system.setText(entry.getStation().getSystem().getName());
|
||||||
@@ -172,17 +178,53 @@ public class HelperController {
|
|||||||
refuel.setText(String.valueOf(entry.getRefill()));
|
refuel.setText(String.valueOf(entry.getRefill()));
|
||||||
buyOrders.setItems(entry.orders());
|
buyOrders.setItems(entry.orders());
|
||||||
sellOrders.setItems(entry.sellOrders());
|
sellOrders.setItems(entry.sellOrders());
|
||||||
missions.setItems(entry.missions());
|
missions.setItems(entry.getCompletedMissions());
|
||||||
stations.setItems(FXCollections.observableArrayList(route.getStations(index)));
|
stations.setItems(FXCollections.observableArrayList(route.getStations(index)));
|
||||||
sellOffers.setItems(FXCollections.observableArrayList(route.getSellOffers(index)));
|
sellOffers.setItems(FXCollections.observableArrayList(route.getSellOffers(index)));
|
||||||
Main.copyToClipboard(system.getText());
|
Main.copyToClipboard(system.getText());
|
||||||
|
} else {
|
||||||
|
entry = null;
|
||||||
|
station.setText("");
|
||||||
|
system.setText("No route");
|
||||||
|
time.setText("");
|
||||||
|
refuel.setText("");
|
||||||
|
buyOrders.setItems(FXCollections.emptyObservableList());
|
||||||
|
sellOrders.setItems(FXCollections.emptyObservableList());
|
||||||
|
missions.setItems(FXCollections.emptyObservableList());
|
||||||
|
stations.setItems(FXCollections.emptyObservableList());
|
||||||
|
sellOffers.setItems(FXCollections.emptyObservableList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void complete(){
|
||||||
|
if (route == null) return;
|
||||||
|
ProfileModel profile = MainController.getProfile();
|
||||||
|
boolean isEnd = route.isEnd();
|
||||||
|
RouteEntryModel entry = this.entry;
|
||||||
|
if (profile.isDocked() && MainController.getProfile().getStation().equals(entry.getStation())) {
|
||||||
|
route.complete();
|
||||||
|
if (!isEnd)
|
||||||
|
profile.setDocked(false);
|
||||||
|
else {
|
||||||
|
if (!route.isLoop()) {
|
||||||
|
profile.clearRoute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
profile.setSystem(entry.getStation().getSystem());
|
||||||
|
if (!entry.isTransit()) {
|
||||||
|
profile.setStation(entry.getStation());
|
||||||
|
profile.setDocked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void next(){
|
private void next(){
|
||||||
int index = route.getCurrentEntry();
|
int index = route.getCurrentEntry();
|
||||||
if (index < route.getJumps() - 1){
|
if (index < route.getJumps() - 1){
|
||||||
route.setCurrentEntry(index+1);
|
route.setCurrentEntry(index + 1);
|
||||||
} else {
|
} else {
|
||||||
if (route.isLoop()){
|
if (route.isLoop()){
|
||||||
route.setCurrentEntry(0);
|
route.setCurrentEntry(0);
|
||||||
@@ -194,7 +236,7 @@ public class HelperController {
|
|||||||
private void previous(){
|
private void previous(){
|
||||||
int index = route.getCurrentEntry();
|
int index = route.getCurrentEntry();
|
||||||
if (index > 0){
|
if (index > 0){
|
||||||
route.setCurrentEntry(index-1);
|
route.setCurrentEntry(index - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,11 +252,7 @@ public class HelperController {
|
|||||||
|
|
||||||
private final ChangeListener<? super Number> currentEntryListener = (ov, o, n) -> ViewUtils.doFX(() -> setRouteEntry(n.intValue()));
|
private final ChangeListener<? super Number> currentEntryListener = (ov, o, n) -> ViewUtils.doFX(() -> setRouteEntry(n.intValue()));
|
||||||
private final ChangeListener<Boolean> dockedListener = (ov, o, n) -> ViewUtils.doFX(() -> setDocked(n));
|
private final ChangeListener<Boolean> dockedListener = (ov, o, n) -> ViewUtils.doFX(() -> setDocked(n));
|
||||||
private final ChangeListener<RouteModel> routeListener = (ov, o, n) -> {
|
private final ChangeListener<RouteModel> routeListener = (ov, o, n) -> ViewUtils.doFX(() -> setRoute(n));
|
||||||
if (n != null){
|
|
||||||
ViewUtils.doFX(() -> setRoute(n));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private void addDragListeners(final Node node){
|
private void addDragListeners(final Node node){
|
||||||
new DragListener(node);
|
new DragListener(node);
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
package ru.trader.model;
|
package ru.trader.model;
|
||||||
|
|
||||||
import ru.trader.analysis.CrawlerSpecificator;
|
import ru.trader.analysis.CrawlerSpecificator;
|
||||||
|
import ru.trader.analysis.RouteReserve;
|
||||||
import ru.trader.core.Offer;
|
import ru.trader.core.Offer;
|
||||||
import ru.trader.store.simple.SimpleOffer;
|
import ru.trader.store.simple.SimpleOffer;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
public class MissionModel {
|
public class MissionModel {
|
||||||
private final StationModel target;
|
private final StationModel target;
|
||||||
private final ItemModel item;
|
private final ItemModel item;
|
||||||
private final long count;
|
private final long count;
|
||||||
private final double profit;
|
private final double profit;
|
||||||
private final Offer offer;
|
private final Offer offer;
|
||||||
|
private long need;
|
||||||
|
private Collection<RouteReserve> reserves;
|
||||||
|
|
||||||
public MissionModel(StationModel target, double profit) {
|
public MissionModel(StationModel target, double profit) {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
@@ -17,6 +22,7 @@ public class MissionModel {
|
|||||||
item = null;
|
item = null;
|
||||||
count = 0;
|
count = 0;
|
||||||
offer = null;
|
offer = null;
|
||||||
|
need = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MissionModel(StationModel target, long count, double profit) {
|
public MissionModel(StationModel target, long count, double profit) {
|
||||||
@@ -25,6 +31,7 @@ public class MissionModel {
|
|||||||
this.profit = profit;
|
this.profit = profit;
|
||||||
this.item = null;
|
this.item = null;
|
||||||
offer = null;
|
offer = null;
|
||||||
|
need = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -34,6 +41,7 @@ public class MissionModel {
|
|||||||
this.count = count;
|
this.count = count;
|
||||||
this.profit = profit;
|
this.profit = profit;
|
||||||
offer = SimpleOffer.fakeBuy(target.getStation(), item.getItem(), profit/count, count);
|
offer = SimpleOffer.fakeBuy(target.getStation(), item.getItem(), profit/count, count);
|
||||||
|
need = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StationModel getTarget() {
|
public StationModel getTarget() {
|
||||||
@@ -86,4 +94,31 @@ public class MissionModel {
|
|||||||
Offer getOffer(){
|
Offer getOffer(){
|
||||||
return offer;
|
return offer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collection<RouteReserve> getReserves() {
|
||||||
|
return reserves;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setReserves(Collection<RouteReserve> reserves) {
|
||||||
|
assert this.reserves == null;
|
||||||
|
this.reserves = reserves;
|
||||||
|
}
|
||||||
|
|
||||||
|
void complete(Collection<OrderModel> orders){
|
||||||
|
if (isSupply()){
|
||||||
|
for (OrderModel order : orders) {
|
||||||
|
if (item.equals(order.getOffer().getItem()) && target.equals(order.getBuyer())){
|
||||||
|
for (RouteReserve reserve : reserves) {
|
||||||
|
if (order.getOffer().getOffer().equals(reserve.getOrder().getSell())){
|
||||||
|
need -= order.getCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCompleted(){
|
||||||
|
return need <= 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,6 +224,10 @@ public class ProfileModel {
|
|||||||
return profile.getShip().getEmptyMaxJumpRange();
|
return profile.getShip().getEmptyMaxJumpRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearRoute(){
|
||||||
|
route.setValue(null);
|
||||||
|
}
|
||||||
|
|
||||||
private void refresh(){
|
private void refresh(){
|
||||||
name.setValue(profile.getName());
|
name.setValue(profile.getName());
|
||||||
balance.setValue(profile.getBalance());
|
balance.setValue(profile.getBalance());
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import javafx.beans.property.ReadOnlyDoubleProperty;
|
|||||||
import javafx.beans.property.SimpleDoubleProperty;
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.collections.transformation.FilteredList;
|
||||||
import ru.trader.analysis.RouteEntry;
|
import ru.trader.analysis.RouteEntry;
|
||||||
import ru.trader.core.Order;
|
import ru.trader.core.Order;
|
||||||
import ru.trader.model.support.BindingsHelper;
|
import ru.trader.model.support.BindingsHelper;
|
||||||
@@ -103,6 +104,10 @@ public class RouteEntryModel {
|
|||||||
return missions;
|
return missions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ObservableList<MissionModel> getCompletedMissions() {
|
||||||
|
return new FilteredList<>(missions, MissionModel::isCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
void refresh(MarketModel market){
|
void refresh(MarketModel market){
|
||||||
orders.clear();
|
orders.clear();
|
||||||
orders.addAll(BindingsHelper.observableList(entry.getOrders(), market.getModeler()::get));
|
orders.addAll(BindingsHelper.observableList(entry.getOrders(), market.getModeler()::get));
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ public class RouteModel {
|
|||||||
Collection<RouteReserve> reserves = RouteFiller.getReserves(_route, offset, offer);
|
Collection<RouteReserve> reserves = RouteFiller.getReserves(_route, offset, offer);
|
||||||
if (!reserves.isEmpty()) {
|
if (!reserves.isEmpty()) {
|
||||||
_route.reserve(reserves);
|
_route.reserve(reserves);
|
||||||
|
mission.setReserves(reserves);
|
||||||
completeIndex = RouteReserve.getCompleteIndex(reserves, offset);
|
completeIndex = RouteReserve.getCompleteIndex(reserves, offset);
|
||||||
for (RouteEntryModel entry : entries) {
|
for (RouteEntryModel entry : entries) {
|
||||||
entry.sellOrders().clear();
|
entry.sellOrders().clear();
|
||||||
@@ -158,6 +159,7 @@ public class RouteModel {
|
|||||||
RouteReserve reserve = RouteFiller.getReserves(_route, offset, mission.getTarget().getStation(), mission.getCount());
|
RouteReserve reserve = RouteFiller.getReserves(_route, offset, mission.getTarget().getStation(), mission.getCount());
|
||||||
if (reserve != null) {
|
if (reserve != null) {
|
||||||
_route.reserve(reserve);
|
_route.reserve(reserve);
|
||||||
|
mission.setReserves(Collections.singleton(reserve));
|
||||||
completeIndex = reserve.getToIndex();
|
completeIndex = reserve.getToIndex();
|
||||||
for (RouteEntryModel entry : entries) {
|
for (RouteEntryModel entry : entries) {
|
||||||
entry.refresh(market);
|
entry.refresh(market);
|
||||||
@@ -180,6 +182,7 @@ public class RouteModel {
|
|||||||
Collection<RouteReserve> reserves = RouteFiller.getReserves(_route, offset, offer);
|
Collection<RouteReserve> reserves = RouteFiller.getReserves(_route, offset, offer);
|
||||||
if (!reserves.isEmpty()) {
|
if (!reserves.isEmpty()) {
|
||||||
_route.reserve(reserves);
|
_route.reserve(reserves);
|
||||||
|
mission.setReserves(reserves);
|
||||||
completeIndex = RouteReserve.getCompleteIndex(reserves, offset);
|
completeIndex = RouteReserve.getCompleteIndex(reserves, offset);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -187,6 +190,7 @@ public class RouteModel {
|
|||||||
RouteReserve reserve = RouteFiller.getReserves(_route, offset, mission.getTarget().getStation(), mission.getCount());
|
RouteReserve reserve = RouteFiller.getReserves(_route, offset, mission.getTarget().getStation(), mission.getCount());
|
||||||
if (reserve != null) {
|
if (reserve != null) {
|
||||||
_route.reserve(reserve);
|
_route.reserve(reserve);
|
||||||
|
mission.setReserves(Collections.singleton(reserve));
|
||||||
completeIndex = reserve.getToIndex();
|
completeIndex = reserve.getToIndex();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -198,11 +202,7 @@ public class RouteModel {
|
|||||||
entries.get(completeIndex).add(mission);
|
entries.get(completeIndex).add(mission);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (RouteEntryModel entry : entries) {
|
refresh();
|
||||||
entry.sellOrders().clear();
|
|
||||||
entry.refresh(market);
|
|
||||||
}
|
|
||||||
fillSellOrders();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<StationModel> getStations(int offset){
|
public Collection<StationModel> getStations(int offset){
|
||||||
@@ -267,11 +267,10 @@ public class RouteModel {
|
|||||||
setCurrentEntry(index+1);
|
setCurrentEntry(index+1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = index+1; i < entries.size(); i++) {
|
for (int i = index; i < entries.size(); i++) {
|
||||||
entry = entries.get(i);
|
entry = entries.get(i);
|
||||||
if (system.equals(entry.getStation().getSystem())
|
if (system.equals(entry.getStation().getSystem())
|
||||||
&& (station == null || station == ModelFabric.NONE_STATION ||
|
&& (ModelFabric.isFake(station) || station.equals(entry.getStation()))
|
||||||
station.equals(entry.getStation()))
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
setCurrentEntry(i);
|
setCurrentEntry(i);
|
||||||
@@ -283,8 +282,7 @@ public class RouteModel {
|
|||||||
for (int i = 0; i < index-1; i++) {
|
for (int i = 0; i < index-1; i++) {
|
||||||
entry = entries.get(i);
|
entry = entries.get(i);
|
||||||
if (system.equals(entry.getStation().getSystem())
|
if (system.equals(entry.getStation().getSystem())
|
||||||
&& (station == null || station == ModelFabric.NONE_STATION ||
|
&& (ModelFabric.isFake(station) || station.equals(entry.getStation()))
|
||||||
station.equals(entry.getStation()))
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
setCurrentEntry(i);
|
setCurrentEntry(i);
|
||||||
@@ -295,4 +293,55 @@ public class RouteModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void complete(){
|
||||||
|
int index = getCurrentEntry();
|
||||||
|
RouteEntryModel entry = entries.get(index);
|
||||||
|
Collection<OrderModel> orders = entry.orders();
|
||||||
|
for (int i = index+1; i < entries.size(); i++) {
|
||||||
|
RouteEntryModel e = entries.get(i);
|
||||||
|
for (MissionModel mission : e.missions()) {
|
||||||
|
mission.complete(orders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isLoop()){
|
||||||
|
for (int i = 0; i < index; i++) {
|
||||||
|
RouteEntryModel e = entries.get(i);
|
||||||
|
for (MissionModel mission : e.missions()) {
|
||||||
|
mission.complete(orders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collection<MissionModel> missions = new ArrayList<>(entry.missions());
|
||||||
|
boolean needRefresh = false;
|
||||||
|
for (MissionModel mission : missions) {
|
||||||
|
mission.complete(orders);
|
||||||
|
if (mission.isCompleted()){
|
||||||
|
Collection<RouteReserve> reserves = mission.getReserves();
|
||||||
|
if (reserves != null) {
|
||||||
|
needRefresh = true;
|
||||||
|
_route.unreserve(reserves);
|
||||||
|
}
|
||||||
|
entry.remove(mission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needRefresh){
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
if (index == entries.size()-1){
|
||||||
|
if (isLoop()) setCurrentEntry(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnd(){
|
||||||
|
return getCurrentEntry() == entries.size()-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refresh(){
|
||||||
|
for (RouteEntryModel entry : entries) {
|
||||||
|
entry.sellOrders().clear();
|
||||||
|
entry.refresh(market);
|
||||||
|
}
|
||||||
|
fillSellOrders();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,33 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.*?>
|
<?import javafx.scene.control.*?>
|
||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
<?import ru.trader.view.support.cells.OfferListCell?>
|
|
||||||
<?import javafx.geometry.Insets?>
|
|
||||||
<?import ru.trader.view.support.NumberField?>
|
|
||||||
<?import org.controlsfx.glyphfont.Glyph?>
|
<?import org.controlsfx.glyphfont.Glyph?>
|
||||||
<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
|
<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
|
||||||
fx:controller="ru.trader.controllers.HelperController"
|
fx:controller="ru.trader.controllers.HelperController"
|
||||||
spacing="4" maxWidth="160">
|
spacing="4" minWidth="200" fx:id="helper">
|
||||||
<HBox><Label text="Система:" /><Label fx:id="system" /></HBox>
|
<HBox>
|
||||||
<HBox><Label text="Станция:" /><Label fx:id="station" /></HBox>
|
<VBox>
|
||||||
<HBox><Label text="Время:" /><Label fx:id="time" /></HBox>
|
<HBox>
|
||||||
|
<Button onAction="#copy" minWidth="30">
|
||||||
|
<graphic><Glyph text="FontAwesome|COPY" /></graphic>
|
||||||
|
</Button>
|
||||||
|
<Label fx:id="system" text="Breksta" prefWidth="130" maxWidth="130" styleClass="text-big" />
|
||||||
|
<Label fx:id="time" text="0:44:15" styleClass="text-small"/>
|
||||||
|
</HBox>
|
||||||
|
<Label fx:id="station" text="Pieres Market" styleClass="text-medium" />
|
||||||
|
</VBox>
|
||||||
|
</HBox>
|
||||||
<HBox fx:id="refuelGroup"><Label text="Заправить:" /><Label fx:id="refuel" /></HBox>
|
<HBox fx:id="refuelGroup"><Label text="Заправить:" /><Label fx:id="refuel" /></HBox>
|
||||||
|
<HBox>
|
||||||
|
<ToggleButton fx:id="infoBtn" minWidth="30">
|
||||||
|
<graphic><Glyph text="FontAwesome|INFO"/></graphic>
|
||||||
|
</ToggleButton>
|
||||||
|
<Button minWidth="30" onAction="#complete">
|
||||||
|
<graphic><Glyph text="FontAwesome|CHECK_CIRCLE"/></graphic>
|
||||||
|
</Button>
|
||||||
|
</HBox>
|
||||||
<VBox fx:id="ordersGroup" maxHeight="240">
|
<VBox fx:id="ordersGroup" maxHeight="240">
|
||||||
<Label text="Продать:" />
|
<Label text="Продать:" />
|
||||||
<ListView fx:id="sellOrders"/>
|
<ListView fx:id="sellOrders"/>
|
||||||
@@ -30,18 +44,7 @@
|
|||||||
<Label text="Товары:" />
|
<Label text="Товары:" />
|
||||||
<ListView fx:id="sellOffers"/>
|
<ListView fx:id="sellOffers"/>
|
||||||
</VBox>
|
</VBox>
|
||||||
<HBox>
|
<padding>
|
||||||
<Button minWidth="30" onAction="#previous">
|
<Insets top="5" left="5" right="5" bottom="5" />
|
||||||
<graphic><Glyph text="FontAwesome|ARROW_LEFT"/></graphic>
|
</padding>
|
||||||
</Button>
|
|
||||||
<Button minWidth="30" onAction="#next">
|
|
||||||
<graphic><Glyph text="FontAwesome|ARROW_RIGHT"/></graphic>
|
|
||||||
</Button>
|
|
||||||
<Button minWidth="30" onAction="#copy">
|
|
||||||
<graphic><Glyph text="FontAwesome|COPY"/></graphic>
|
|
||||||
</Button>
|
|
||||||
<ToggleButton fx:id="infoBtn" minWidth="30">
|
|
||||||
<graphic><Glyph text="FontAwesome|HELP"/></graphic>
|
|
||||||
</ToggleButton>
|
|
||||||
</HBox>
|
|
||||||
</VBox>
|
</VBox>
|
||||||
|
|||||||
Reference in New Issue
Block a user