Changed action cards logic.
This commit is contained in:
parent
729e259b33
commit
3592547afe
5
pom.xml
5
pom.xml
@ -85,11 +85,6 @@
|
||||
<artifactId>telegrambots-abilities</artifactId>
|
||||
<version>6.7.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-jse</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-math3</artifactId>
|
||||
|
@ -53,4 +53,9 @@ public interface Constants {
|
||||
String INFO_MESSAGE = "Вот открытая информация о живых игроках\n";
|
||||
|
||||
String CANT_SEND_NOT_DAY = "Нельзя использовать эту команду во время перерыва.";
|
||||
String BUNKER_STATS = "В вашем бункере следующая ситуация:\n%s";
|
||||
String RANDOM_HIV = "Затмение венеры (рандомный вич)";
|
||||
String RANDOM_HIV_ENABLED = "Венера взошла для игрока %s";
|
||||
String CHANGE_WORKS = "Обменяться профессиями";
|
||||
String CHANGE_WORKS_TRIGGERED = "Вы обменялись профессиями с игроком %s";
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.alterdekim.javabot.bot;
|
||||
|
||||
import com.alterdekim.javabot.bot.cards.ActionCard;
|
||||
import com.alterdekim.javabot.entities.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
@ -25,7 +26,7 @@ public class Player {
|
||||
private String firstName;
|
||||
private InfoSections infoSections;
|
||||
private Boolean isVoted = false;
|
||||
private List<ActionScript> scripts;
|
||||
private List<Class<? extends ActionCard>> scripts;
|
||||
private Integer scriptMessageId;
|
||||
|
||||
public Player(Long telegramId, String name) {
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.alterdekim.javabot.bot.cards;
|
||||
|
||||
import com.alterdekim.javabot.bot.Player;
|
||||
import com.alterdekim.javabot.components.BunkerBot;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public abstract class ActionCard {
|
||||
BunkerBot bot;
|
||||
Player activator;
|
||||
|
||||
public abstract void execute();
|
||||
|
||||
public abstract String getName();
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.alterdekim.javabot.bot.cards;
|
||||
|
||||
import com.alterdekim.javabot.Constants;
|
||||
import com.alterdekim.javabot.bot.Player;
|
||||
import com.alterdekim.javabot.entities.Work;
|
||||
import com.alterdekim.javabot.util.BotUtils;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
|
||||
|
||||
public class ChangeWorksCard extends ActionCard {
|
||||
@Override
|
||||
public void execute() {
|
||||
Player p = (Player) BotUtils.getRandomFromList(this.bot.players, this.bot.random);
|
||||
Work w = this.activator.getWork();
|
||||
this.activator.setWork(p.getWork());
|
||||
p.setWork(w);
|
||||
this.bot.sendApi(new SendMessage(this.activator.getTelegramId()+"", String.format(Constants.CHANGE_WORKS_TRIGGERED, p.getFirstName())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return Constants.CHANGE_WORKS;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.alterdekim.javabot.bot.cards;
|
||||
|
||||
import com.alterdekim.javabot.Constants;
|
||||
import com.alterdekim.javabot.bot.Player;
|
||||
import com.alterdekim.javabot.util.BotUtils;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
|
||||
|
||||
public class RandomHIVCard extends ActionCard {
|
||||
private static final long HIV_ID = 31;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Player p = (Player) BotUtils.getRandomFromList(this.bot.players, this.bot.random);
|
||||
p.setHealth(this.bot.healthService.getHealthById(HIV_ID));
|
||||
this.bot.sendApi(new SendMessage(this.activator.getTelegramId()+"", String.format(Constants.RANDOM_HIV_ENABLED, p.getFirstName())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return Constants.RANDOM_HIV;
|
||||
}
|
||||
}
|
@ -4,14 +4,14 @@ import com.alterdekim.javabot.bot.*;
|
||||
import com.alterdekim.javabot.Commands;
|
||||
import com.alterdekim.javabot.Constants;
|
||||
import com.alterdekim.javabot.TelegramConfig;
|
||||
import com.alterdekim.javabot.bot.cards.ActionCard;
|
||||
import com.alterdekim.javabot.bot.cards.ChangeWorksCard;
|
||||
import com.alterdekim.javabot.bot.cards.RandomHIVCard;
|
||||
import com.alterdekim.javabot.entities.*;
|
||||
import com.alterdekim.javabot.service.*;
|
||||
import com.alterdekim.javabot.util.*;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||
@ -44,19 +44,19 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
|
||||
private double last_p = -1;
|
||||
|
||||
private List<Player> players;
|
||||
public List<Player> players;
|
||||
|
||||
private final BioService bioService;
|
||||
private final HealthService healthService;
|
||||
public final HealthService healthService;
|
||||
private final HobbyService hobbyService;
|
||||
private final LuggageService luggageService;
|
||||
private final WorkService workService;
|
||||
private final TextDataValService textDataValService;
|
||||
private final DisasterService disasterService;
|
||||
private final SynergyService synergyService;
|
||||
private final ActionScriptsServiceImpl scriptsService;
|
||||
private List<Class<? extends ActionCard>> actionCards;
|
||||
|
||||
private final RandomComponent random;
|
||||
public final RandomComponent random;
|
||||
|
||||
private DayNightFields dayNightFields;
|
||||
|
||||
@ -72,7 +72,6 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
TextDataValService textDataValService,
|
||||
DisasterService disasterService,
|
||||
SynergyService synergyService,
|
||||
ActionScriptsServiceImpl scriptsService,
|
||||
RandomComponent randomComponent) {
|
||||
this.telegramConfig = telegramConfig;
|
||||
this.players = new ArrayList<>();
|
||||
@ -85,7 +84,7 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
this.textDataValService = textDataValService;
|
||||
this.disasterService = disasterService;
|
||||
this.synergyService = synergyService;
|
||||
this.scriptsService = scriptsService;
|
||||
this.actionCards = List.of(RandomHIVCard.class, ChangeWorksCard.class);
|
||||
this.random = randomComponent;
|
||||
this.dayNightFields = new DayNightFields();
|
||||
this.linkedQueue = new ConcurrentLinkedQueue<>();
|
||||
@ -180,7 +179,7 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
private void startGame() {
|
||||
if( gameState != GameState.JOINING )
|
||||
return;
|
||||
if(players.size() < 2) { // TODO: change to 2
|
||||
if(players.size() < 1) { // TODO: change to 2
|
||||
sendApi(new SendMessage(groupId, Constants.PLAYERS_LESS_THAN_ZERO));
|
||||
return;
|
||||
}
|
||||
@ -188,12 +187,12 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
this.gameState = GameState.STARTED;
|
||||
Disaster d = (Disaster) BotUtils.getRandomFromList(disasterService.getAllDisasters(), random);
|
||||
sendApi(new SendMessage(groupId, getStringById(d.getDescTextId())));
|
||||
//sendApi(new SendMessage(groupId, String.format(Constants.BUNKER_STATS, )));
|
||||
List<Bio> bios = bioService.getAllBios();
|
||||
List<Work> works = workService.getAllWorks();
|
||||
List<Luggage> luggs = luggageService.getAllLuggages();
|
||||
List<Hobby> hobbies = hobbyService.getAllHobbies();
|
||||
List<Health> healths = healthService.getAllHealth();
|
||||
List<ActionScript> scripts = scriptsService.getAllActionScripts();
|
||||
for( int i = 0; i < players.size(); i++ ) {
|
||||
players.get(i).setAge(random.nextInt(57)+18);
|
||||
players.get(i).setGender((Bio) BotUtils.getRandomFromList(bios, random));
|
||||
@ -201,13 +200,12 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
players.get(i).setLuggage((Luggage) BotUtils.getRandomFromList(luggs, random));
|
||||
players.get(i).setHobby((Hobby) BotUtils.getRandomFromList(hobbies, random));
|
||||
players.get(i).setHealth((Health) BotUtils.getRandomFromList(healths, random));
|
||||
if( (random.nextInt(100) >= 45 || (i == (players.size()-1) && isNoOneHasScripts())) && !scripts.isEmpty() ) {
|
||||
ActionScript asc = (ActionScript) BotUtils.getRandomFromList(scripts, random);
|
||||
//ActionScript asc = scripts.get(scripts.size()-1);
|
||||
scripts.removeIf(p -> p.getId().longValue() == asc.getId().longValue());
|
||||
if( (random.nextInt(100) >= 45 || (i == (players.size()-1) && isNoOneHasScripts())) && !this.actionCards.isEmpty() ) {
|
||||
Class<? extends ActionCard> asc = (Class<? extends ActionCard>) BotUtils.getRandomFromList(this.actionCards, random);
|
||||
this.actionCards.removeIf(p -> p.getCanonicalName().equals(asc.getCanonicalName()));
|
||||
players.get(i).setScripts(Collections.singletonList(asc));
|
||||
} else {
|
||||
players.get(i).setScripts(new ArrayList<>());
|
||||
players.get(i).setScripts(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
doNight();
|
||||
@ -226,7 +224,7 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
sendApi(sendMessage);
|
||||
if( p.getScripts().isEmpty() ) continue;
|
||||
sendMessage = new SendMessage(p.getTelegramId()+"", Constants.SCRIPT_MESSAGE);
|
||||
sendMessage.setReplyMarkup(BotUtils.getScriptKeyboard(p.getScripts(), textDataValService));
|
||||
sendMessage.setReplyMarkup(BotUtils.getScriptKeyboard(p.getScripts()));
|
||||
try {
|
||||
setScriptMessageId(p, sendApiMethod(sendMessage).getMessageId());
|
||||
} catch (Exception e) {
|
||||
@ -247,8 +245,16 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
}
|
||||
|
||||
private void processNightScriptButton(Player p, CallbackQuery callbackQuery, String data) {
|
||||
ActionScript script = p.getScripts().stream()
|
||||
.filter(s -> HashUtils.getCRC32(textDataValService.getTextDataValById(s.getTextNameId()).getText().getBytes()).equals(data))
|
||||
Class<? extends ActionCard> script = p.getScripts().stream()
|
||||
.filter(s -> {
|
||||
try {
|
||||
return HashUtils.getCRC32(s.getDeclaredConstructor().newInstance().getName().getBytes()).equals(data);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if( script == null ) return;
|
||||
@ -256,24 +262,11 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
sendApi(new SendMessage(groupId, String.format(Constants.PRESSED_SCRIPT_NIGHT, callbackQuery.getFrom().getFirstName())));
|
||||
sendApi(new SendMessage(callbackQuery.getMessage().getChatId()+"", Constants.THANK_YOU));
|
||||
p.setScripts(new ArrayList<>());
|
||||
executeLuaScript(script, p);
|
||||
try {
|
||||
script.getDeclaredConstructor(BunkerBot.class, Player.class).newInstance(this, p).execute();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
|
||||
private void executeLuaScript(ActionScript script, Player p) {
|
||||
Globals globals = JsePlatform.standardGlobals();
|
||||
globals.set("players", LuaSerializer.serializeObjectList(players));
|
||||
globals.set("player", LuaSerializer.serializeObject(p));
|
||||
globals.set("genders", LuaSerializer.serializeObjectList(bioService.getAllBios()));
|
||||
globals.set("hobbies", LuaSerializer.serializeObjectList(hobbyService.getAllHobbies()));
|
||||
globals.set("healths", LuaSerializer.serializeObjectList(healthService.getAllHealth()));
|
||||
globals.set("luggages", LuaSerializer.serializeObjectList(luggageService.getAllLuggages()));
|
||||
globals.set("works", LuaSerializer.serializeObjectList(workService.getAllWorks()));
|
||||
LuaValue chunk = globals.load(script.getScriptBody());
|
||||
chunk.call();
|
||||
this.players = LuaDeserializer.deserializePlayers(globals.get("players"))
|
||||
.stream()
|
||||
.peek(p1 -> p1.setScripts(getPlayerById(p1.getTelegramId()).getScripts()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void processNightButton(CallbackQuery callbackQuery) {
|
||||
@ -333,7 +326,7 @@ public class BunkerBot extends TelegramLongPollingBot {
|
||||
}
|
||||
}
|
||||
|
||||
private void sendApi(BotApiMethod<? extends Serializable> method) {
|
||||
public void sendApi(BotApiMethod<? extends Serializable> method) {
|
||||
this.linkedQueue.add(method);
|
||||
}
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
package com.alterdekim.javabot.entities;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
@ToString
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "action_scripts")
|
||||
public class ActionScript {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Long textNameId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Long textDescId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String scriptBody;
|
||||
|
||||
public ActionScript(Long textNameId, Long textDescId, String scriptBody) {
|
||||
this.textNameId = textNameId;
|
||||
this.textDescId = textDescId;
|
||||
this.scriptBody = scriptBody;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package com.alterdekim.javabot.entities;
|
||||
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
@ToString
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "action_scripts_req")
|
||||
public class ActionScriptRequest {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String textName;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String textDesc;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String scriptBody;
|
||||
|
||||
public ActionScriptRequest(String textName, String textDesc, String scriptBody) {
|
||||
this.textName = textName;
|
||||
this.textDesc = textDesc;
|
||||
this.scriptBody = scriptBody;
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package com.alterdekim.javabot.repository;
|
||||
|
||||
import com.alterdekim.javabot.entities.ActionScript;
|
||||
import com.alterdekim.javabot.entities.ActionScriptRequest;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ActionScriptRequestsRepository extends JpaRepository<ActionScriptRequest, Long> {
|
||||
Optional<ActionScriptRequest> findById(Long id);
|
||||
|
||||
List<ActionScriptRequest> findAll();
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package com.alterdekim.javabot.repository;
|
||||
|
||||
import com.alterdekim.javabot.entities.ActionScript;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ActionScriptsRepository extends JpaRepository<ActionScript, Long> {
|
||||
Optional<ActionScript> findById(Long id);
|
||||
|
||||
List<ActionScript> findAll();
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package com.alterdekim.javabot.service;
|
||||
|
||||
import com.alterdekim.javabot.entities.ActionScript;
|
||||
import com.alterdekim.javabot.entities.ActionScriptRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ActionRequestService {
|
||||
List<ActionScriptRequest> getAllActionScripts();
|
||||
ActionScriptRequest getActionScriptById(long scriptId);
|
||||
void removeById(long scriptId);
|
||||
void saveScript(ActionScriptRequest script);
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package com.alterdekim.javabot.service;
|
||||
|
||||
import com.alterdekim.javabot.entities.ActionScript;
|
||||
import com.alterdekim.javabot.entities.Luggage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ActionScriptsService {
|
||||
List<ActionScript> getAllActionScripts();
|
||||
ActionScript getActionScriptById(long scriptId);
|
||||
void removeById(long scriptId);
|
||||
void saveScript(ActionScript script);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package com.alterdekim.javabot.service;
|
||||
|
||||
import com.alterdekim.javabot.entities.ActionScript;
|
||||
import com.alterdekim.javabot.repository.ActionScriptsRepository;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class ActionScriptsServiceImpl implements ActionScriptsService {
|
||||
|
||||
private final ActionScriptsRepository actionScriptsRepository;
|
||||
|
||||
@Override
|
||||
public List<ActionScript> getAllActionScripts() {
|
||||
return actionScriptsRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionScript getActionScriptById(long scriptId) {
|
||||
return actionScriptsRepository.findById(scriptId).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeById(long scriptId) {
|
||||
actionScriptsRepository.deleteById(scriptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveScript(ActionScript script) {
|
||||
actionScriptsRepository.save(script);
|
||||
}
|
||||
}
|
@ -3,16 +3,17 @@ package com.alterdekim.javabot.util;
|
||||
import com.alterdekim.javabot.Constants;
|
||||
import com.alterdekim.javabot.bot.InfoSections;
|
||||
import com.alterdekim.javabot.bot.SectionType;
|
||||
import com.alterdekim.javabot.bot.cards.ActionCard;
|
||||
import com.alterdekim.javabot.components.RandomComponent;
|
||||
import com.alterdekim.javabot.entities.ActionScript;
|
||||
import com.alterdekim.javabot.service.TextDataValService;
|
||||
import com.alterdekim.javabot.service.TextDataValServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
|
||||
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class BotUtils {
|
||||
public static InlineKeyboardMarkup getJoinKeyboard() {
|
||||
InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();
|
||||
@ -77,13 +78,18 @@ public class BotUtils {
|
||||
return inlineKeyboardMarkup;
|
||||
}
|
||||
|
||||
public static InlineKeyboardMarkup getScriptKeyboard(List<ActionScript> scripts, TextDataValService textDataValService) {
|
||||
public static InlineKeyboardMarkup getScriptKeyboard(List<Class<? extends ActionCard>> scripts) {
|
||||
InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();
|
||||
inlineKeyboardMarkup.setKeyboard(scripts.stream()
|
||||
.map(s -> {
|
||||
InlineKeyboardButton inlineKeyboardButton = new InlineKeyboardButton();
|
||||
inlineKeyboardButton.setText(textDataValService.getTextDataValById(s.getTextNameId()).getText());
|
||||
inlineKeyboardButton.setCallbackData(HashUtils.getCRC32(textDataValService.getTextDataValById(s.getTextNameId()).getText().getBytes()));
|
||||
try {
|
||||
inlineKeyboardButton.setText(s.getDeclaredConstructor().newInstance().getName());
|
||||
inlineKeyboardButton.setCallbackData(HashUtils.getCRC32(s.getDeclaredConstructor().newInstance().getName().getBytes()));
|
||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
|
||||
InvocationTargetException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
return Collections.singletonList(inlineKeyboardButton);
|
||||
}).collect(Collectors.toList()));
|
||||
return inlineKeyboardMarkup;
|
||||
|
@ -42,12 +42,12 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/panel?section=stats" th:text="#{stats}"></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<!--<li class="nav-item">
|
||||
<a class="nav-link" href="/panel?section=actions" th:text="#{actions}"></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
</li>-->
|
||||
<!--<li class="nav-item">
|
||||
<a class="nav-link" href="/panel?section=script_request" th:text="#{scrireqq}"></a>
|
||||
</li>
|
||||
</li>-->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/panel?section=themes" th:text="#{themes}"></a>
|
||||
</li>
|
||||
|
Loading…
x
Reference in New Issue
Block a user