mirror of
https://github.com/alexcrea/CustomAnvil.git
synced 2026-06-24 00:26:16 +02:00
remove legacy enchantment plugins
This commit is contained in:
parent
f17c8b61ab
commit
c8597986a2
7 changed files with 12 additions and 367 deletions
|
|
@ -1,46 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.wrapped;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.Definition;
|
||||
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class CAEEPreV5Enchantment extends CABukkitEnchantment implements AdditionalTestEnchantment {
|
||||
|
||||
@NotNull CustomEnchantment eeenchantment;
|
||||
@NotNull Definition definition;
|
||||
|
||||
public CAEEPreV5Enchantment(@NotNull CustomEnchantment enchantment) {
|
||||
super(enchantment.getBukkitEnchantment(), EnchantmentRarity.getRarity(enchantment.getDefinition().getAnvilCost()));
|
||||
this.eeenchantment = enchantment;
|
||||
this.definition = (Definition) enchantment.getDefinition();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
|
||||
if (!definition.hasConflicts()) return false;
|
||||
|
||||
Set<String> conflicts = definition.getConflicts();
|
||||
|
||||
for (CAEnchantment caEnchantment : enchantments.keySet()) {
|
||||
if (conflicts.contains(caEnchantment.getName())) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat, @NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.equals(itemMat)) return false;
|
||||
|
||||
return !definition.getSupportedItems().is(item);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.wrapped;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import su.nightexpress.excellentenchants.api.enchantment.EnchantmentData;
|
||||
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class CALegacyEEEnchantment extends CABukkitEnchantment implements AdditionalTestEnchantment {
|
||||
|
||||
@NotNull EnchantmentData eeenchantment;
|
||||
|
||||
public CALegacyEEEnchantment(@NotNull EnchantmentData enchantment) {
|
||||
super(enchantment.getEnchantment(), EnchantmentRarity.getRarity(enchantment.getAnvilCost()));
|
||||
this.eeenchantment = enchantment;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
|
||||
if (!eeenchantment.hasConflicts()) return false;
|
||||
|
||||
Set<String> conflicts = eeenchantment.getConflicts();
|
||||
|
||||
for (CAEnchantment caEnchantment : enchantments.keySet()) {
|
||||
if (conflicts.contains(caEnchantment.getName())) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat, @NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.equals(itemMat)) return false;
|
||||
|
||||
return !eeenchantment.getSupportedItems().is(item);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.enchant.wrapped;
|
||||
|
||||
import com.willfp.ecoenchants.enchantments.EcoEnchant;
|
||||
import com.willfp.ecoenchants.enchantments.meta.EnchantmentTarget;
|
||||
import com.willfp.ecoenchants.enchantments.meta.EnchantmentType;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
|
||||
import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class CALegacyEcoEnchant extends CABukkitEnchantment implements AdditionalTestEnchantment {
|
||||
|
||||
private final @NotNull EcoEnchant ecoEnchant;
|
||||
|
||||
public CALegacyEcoEnchant(@NotNull EcoEnchant ecoEnchant, @NotNull Enchantment enchantment) {
|
||||
super(enchantment, EnchantmentRarity.COMMON);
|
||||
this.ecoEnchant = ecoEnchant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnchantConflict(@NotNull Map<CAEnchantment, Integer> enchantments, @NotNull Material itemMat) {
|
||||
if (enchantments.isEmpty()) return false;
|
||||
|
||||
EnchantmentType type = this.ecoEnchant.getType();
|
||||
boolean isSingular = type.isSingular();
|
||||
|
||||
for (CAEnchantment other : enchantments.keySet()) {
|
||||
if (other instanceof CABukkitEnchantment otherVanilla
|
||||
&& this.ecoEnchant.conflictsWith(otherVanilla.getEnchant())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isSingular &&
|
||||
other != this &&
|
||||
(other instanceof CALegacyEcoEnchant otherEco) &&
|
||||
type.equals(otherEco.ecoEnchant.getType())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemConflict(@NotNull Map<CAEnchantment, Integer> enchantments,
|
||||
@NotNull Material itemMat,
|
||||
@NotNull ItemStack item) {
|
||||
if (Material.ENCHANTED_BOOK.equals(itemMat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EnchantmentTarget target : this.ecoEnchant.getTargets()) {
|
||||
if (target.getMaterials().contains(itemMat)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -204,9 +204,6 @@ object DependencyManager {
|
|||
// Test heaven bags used prepare anvil
|
||||
if (!bypass && (havenBagsCompatibility?.testPrepareAnvil(event, player) == true)) bypass = true
|
||||
|
||||
// Test excellent enchantments used prepare anvil
|
||||
if (!bypass && (excellentEnchantsCompatibility?.testPrepareAnvil(event) == true)) bypass = true
|
||||
|
||||
for (genericDependency in genericDependencies) {
|
||||
if (!bypass && genericDependency.testPrepareAnvil(event)) bypass = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,26 +12,8 @@ import xyz.alexcrea.cuanvil.enchant.wrapped.CAEcoEnchant
|
|||
|
||||
class EcoEnchantDependency(private val ecoEnchantPlugin: Plugin) {
|
||||
|
||||
private val isLegacy: Boolean
|
||||
private val legacyDependency: LegacyEcoEnchantDependency?
|
||||
|
||||
init {
|
||||
CustomAnvil.instance.logger.info("Eco Enchant Detected !")
|
||||
|
||||
var isLegacy = true
|
||||
try {
|
||||
Class.forName("com.willfp.ecoenchants.enchant.EcoEnchants")
|
||||
isLegacy = false
|
||||
} catch (_: ClassNotFoundException) {
|
||||
}
|
||||
|
||||
this.isLegacy = isLegacy;
|
||||
if (isLegacy) {
|
||||
this.legacyDependency = LegacyEcoEnchantDependency()
|
||||
} else {
|
||||
this.legacyDependency = null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public fun getEcoLevelLimit(): Int {
|
||||
|
|
@ -46,11 +28,6 @@ class EcoEnchantDependency(private val ecoEnchantPlugin: Plugin) {
|
|||
fun registerEnchantments() {
|
||||
CustomAnvil.instance.logger.info("Preparing Eco Enchant compatibility...")
|
||||
|
||||
if (isLegacy) {
|
||||
legacyDependency!!.registerEnchantments();
|
||||
return
|
||||
}
|
||||
|
||||
val enchantments = EcoEnchants.values()
|
||||
for (ecoEnchant in enchantments) {
|
||||
EnchantmentApi.unregisterEnchantment(ecoEnchant.enchantment) // As eco enchants is loaded before custom anvil and register enchantment to registry, we need to unregister old "vanilla" enchant.
|
||||
|
|
@ -63,11 +40,6 @@ class EcoEnchantDependency(private val ecoEnchantPlugin: Plugin) {
|
|||
}
|
||||
|
||||
fun handleConfigReload() {
|
||||
if (isLegacy) {
|
||||
legacyDependency!!.handleConfigReload()
|
||||
return
|
||||
}
|
||||
|
||||
// Should not happen in known case.
|
||||
if (this.ecoEnchantOldEnchantments == null) return
|
||||
|
||||
|
|
|
|||
|
|
@ -2,105 +2,36 @@ package xyz.alexcrea.cuanvil.dependency.plugins
|
|||
|
||||
import io.delilaheve.CustomAnvil
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.plugin.RegisteredListener
|
||||
import xyz.alexcrea.cuanvil.api.EnchantmentApi
|
||||
import xyz.alexcrea.cuanvil.api.event.listener.CATreatAnvilResultEvent
|
||||
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEPreV5Enchantment
|
||||
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEV5Enchantment
|
||||
import xyz.alexcrea.cuanvil.enchant.wrapped.CALegacyEEEnchantment
|
||||
import java.lang.reflect.Method
|
||||
import su.nightexpress.excellentenchants.api.EnchantRegistry as V5EnchantRegistry
|
||||
import su.nightexpress.excellentenchants.enchantment.impl.universal.CurseOfFragilityEnchant as LegacyCurseOfFragilityEnchant
|
||||
import su.nightexpress.excellentenchants.manager.listener.AnvilListener as V5AnvilListener
|
||||
import su.nightexpress.excellentenchants.enchantment.listener.AnvilListener as PreV5AnvilListener
|
||||
import su.nightexpress.excellentenchants.enchantment.listener.EnchantAnvilListener as LegacyAnvilListener
|
||||
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry as LegacyEnchantRegistry
|
||||
import su.nightexpress.excellentenchants.registry.EnchantRegistry as PreV5EnchantRegistry
|
||||
|
||||
// I don't like that I need to support older version. if I could just drop older support it would be sooo nice
|
||||
class ExcellentEnchantsDependency {
|
||||
|
||||
enum class ListenerVersion(val classPath: String) {
|
||||
V5("su.nightexpress.excellentenchants.manager.listener.AnvilListener"),
|
||||
PRE_V5("su.nightexpress.excellentenchants.enchantment.listener.AnvilListener"),
|
||||
LEGACY("su.nightexpress.excellentenchants.enchantment.listener.EnchantAnvilListener"),
|
||||
}
|
||||
|
||||
private val listenerVersion: ListenerVersion?
|
||||
private val isModernCurseOfFragility: Boolean
|
||||
|
||||
init {
|
||||
CustomAnvil.instance.logger.info("Excellent Enchants Detected !")
|
||||
|
||||
var listenerVersion: ListenerVersion? = null
|
||||
for (value in ListenerVersion.entries) {
|
||||
try {
|
||||
Class.forName(value.classPath)
|
||||
|
||||
listenerVersion = value
|
||||
break
|
||||
} catch (ignored: ClassNotFoundException) {
|
||||
}
|
||||
}
|
||||
|
||||
if (listenerVersion == null) {
|
||||
CustomAnvil.instance.logger.severe("Found issue with listener of Excellent Enchants. compatiblity is broken. please contact CustomAnvil devs")
|
||||
}
|
||||
|
||||
var isModernCurseOfFragility = true
|
||||
try {
|
||||
Class.forName("su.nightexpress.excellentenchants.enchantment.universal.CurseOfFragilityEnchant")
|
||||
} catch (ignored: ClassNotFoundException) {
|
||||
isModernCurseOfFragility = false
|
||||
}
|
||||
|
||||
this.listenerVersion = listenerVersion
|
||||
this.isModernCurseOfFragility = isModernCurseOfFragility
|
||||
}
|
||||
|
||||
fun registerEnchantments() {
|
||||
CustomAnvil.instance.logger.info("Preparing Excellent Enchants compatibility...")
|
||||
|
||||
// As excellent enchants is loaded before custom anvil and register enchantment to registry, we need to unregister old "vanilla" enchant.
|
||||
when (listenerVersion) {
|
||||
ListenerVersion.V5 -> {
|
||||
for (enchantment in V5EnchantRegistry.getRegistered()) {
|
||||
EnchantmentApi.unregisterEnchantment(enchantment.bukkitEnchantment.key)
|
||||
EnchantmentApi.registerEnchantment(CAEEV5Enchantment(enchantment))
|
||||
}
|
||||
}
|
||||
|
||||
ListenerVersion.PRE_V5 -> {
|
||||
for (enchantment in PreV5EnchantRegistry.getRegistered()) {
|
||||
EnchantmentApi.unregisterEnchantment(enchantment.bukkitEnchantment.key)
|
||||
EnchantmentApi.registerEnchantment(CAEEPreV5Enchantment(enchantment))
|
||||
}
|
||||
}
|
||||
|
||||
ListenerVersion.LEGACY -> {
|
||||
for (enchantment in LegacyEnchantRegistry.getRegistered()) {
|
||||
EnchantmentApi.unregisterEnchantment(enchantment.enchantment.key)
|
||||
EnchantmentApi.registerEnchantment(CALegacyEEEnchantment(enchantment))
|
||||
}
|
||||
}
|
||||
|
||||
null -> return
|
||||
|
||||
for (enchantment in V5EnchantRegistry.getRegistered()) {
|
||||
EnchantmentApi.unregisterEnchantment(enchantment.bukkitEnchantment.key)
|
||||
EnchantmentApi.registerEnchantment(CAEEV5Enchantment(enchantment))
|
||||
}
|
||||
|
||||
CustomAnvil.instance.logger.info("Excellent Enchants should now work as expected !")
|
||||
}
|
||||
|
||||
private var legacyFragilityCurse: LegacyCurseOfFragilityEnchant? = null
|
||||
|
||||
private var v5AnvilListener: V5AnvilListener? = null
|
||||
private var preV5AnvilListener: PreV5AnvilListener? = null
|
||||
private var legacyAnvilListener: LegacyAnvilListener? = null
|
||||
private lateinit var usedAnvilListener: Listener
|
||||
private lateinit var anvilListener: V5AnvilListener
|
||||
|
||||
private lateinit var handleRechargeMethod: Method
|
||||
private lateinit var handleCombineMethod: Method
|
||||
|
|
@ -111,66 +42,30 @@ class ExcellentEnchantsDependency {
|
|||
for (registeredListener in PrepareAnvilEvent.getHandlerList().registeredListeners) {
|
||||
val listener = registeredListener.listener
|
||||
|
||||
if (!isModernCurseOfFragility) {
|
||||
if (listener is LegacyCurseOfFragilityEnchant) {
|
||||
this.legacyFragilityCurse = listener
|
||||
toUnregister.add(registeredListener)
|
||||
}
|
||||
if (listener is V5AnvilListener) {
|
||||
this.anvilListener = listener
|
||||
toUnregister.add(registeredListener)
|
||||
}
|
||||
|
||||
when (listenerVersion) {
|
||||
ListenerVersion.V5 -> {
|
||||
if (listener is V5AnvilListener) {
|
||||
this.v5AnvilListener = listener
|
||||
toUnregister.add(registeredListener)
|
||||
}
|
||||
}
|
||||
|
||||
ListenerVersion.PRE_V5 -> {
|
||||
if (listener is PreV5AnvilListener) {
|
||||
this.preV5AnvilListener = listener
|
||||
toUnregister.add(registeredListener)
|
||||
}
|
||||
}
|
||||
|
||||
ListenerVersion.LEGACY -> {
|
||||
if (listener is LegacyAnvilListener) {
|
||||
this.legacyAnvilListener = listener
|
||||
toUnregister.add(registeredListener)
|
||||
}
|
||||
}
|
||||
|
||||
null -> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (listener in toUnregister) {
|
||||
PrepareAnvilEvent.getHandlerList().unregister(listener)
|
||||
}
|
||||
|
||||
when (listenerVersion) {
|
||||
ListenerVersion.V5 -> this.usedAnvilListener = v5AnvilListener!!
|
||||
ListenerVersion.PRE_V5 -> this.usedAnvilListener = preV5AnvilListener!!
|
||||
ListenerVersion.LEGACY -> this.usedAnvilListener = legacyAnvilListener!!
|
||||
null -> {}
|
||||
}
|
||||
|
||||
// Unregister inventory click event
|
||||
InventoryClickEvent.getHandlerList().unregister(this.usedAnvilListener)
|
||||
InventoryClickEvent.getHandlerList().unregister(this.anvilListener)
|
||||
|
||||
findAnvilFunctions()
|
||||
}
|
||||
|
||||
private fun findAnvilFunctions() {
|
||||
this.handleRechargeMethod = this.usedAnvilListener.javaClass.getDeclaredMethod(
|
||||
this.handleRechargeMethod = this.anvilListener.javaClass.getDeclaredMethod(
|
||||
"handleRecharge",
|
||||
PrepareAnvilEvent::class.java, ItemStack::class.java, ItemStack::class.java
|
||||
)
|
||||
this.handleRechargeMethod.setAccessible(true)
|
||||
|
||||
this.handleCombineMethod = this.usedAnvilListener.javaClass.getDeclaredMethod(
|
||||
this.handleCombineMethod = this.anvilListener.javaClass.getDeclaredMethod(
|
||||
"handleCombine",
|
||||
PrepareAnvilEvent::class.java, ItemStack::class.java, ItemStack::class.java, ItemStack::class.java
|
||||
)
|
||||
|
|
@ -178,20 +73,6 @@ class ExcellentEnchantsDependency {
|
|||
|
||||
}
|
||||
|
||||
fun testPrepareAnvil(event: PrepareAnvilEvent): Boolean {
|
||||
if (event.result != null) {
|
||||
if (!isModernCurseOfFragility) {
|
||||
this.legacyFragilityCurse?.onItemAnvil(event)
|
||||
}
|
||||
if (event.result == null) return true
|
||||
}
|
||||
|
||||
val first: ItemStack = treatInput(event.inventory.getItem(0))
|
||||
val second: ItemStack = treatInput(event.inventory.getItem(1))
|
||||
|
||||
return handleRechargeMethod.invoke(this.usedAnvilListener, event, first, second) as Boolean
|
||||
}
|
||||
|
||||
fun treatAnvilResult(event: CATreatAnvilResultEvent) {
|
||||
val result = event.result
|
||||
if (result == null) return
|
||||
|
|
@ -199,17 +80,12 @@ class ExcellentEnchantsDependency {
|
|||
val first: ItemStack = treatInput(event.event.inventory.getItem(0))
|
||||
val second: ItemStack = treatInput(event.event.inventory.getItem(1))
|
||||
|
||||
handleCombineMethod.invoke(this.usedAnvilListener, event.event, first, second, result)
|
||||
handleCombineMethod.invoke(this.anvilListener, event.event, first, second, result)
|
||||
}
|
||||
|
||||
fun testAnvilResult(event: InventoryClickEvent): Any {
|
||||
if (event.inventory.getItem(2) != null) {
|
||||
when (listenerVersion) {
|
||||
ListenerVersion.V5 -> v5AnvilListener!!.onClickAnvil(event)
|
||||
ListenerVersion.PRE_V5 -> preV5AnvilListener!!.onClickAnvil(event)
|
||||
ListenerVersion.LEGACY -> legacyAnvilListener!!.onClickAnvil(event)
|
||||
null -> {}
|
||||
}
|
||||
anvilListener.onClickAnvil(event)
|
||||
return event.inventory.getItem(2) == null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
package xyz.alexcrea.cuanvil.dependency.plugins
|
||||
|
||||
import com.willfp.ecoenchants.enchantments.EcoEnchant
|
||||
import com.willfp.ecoenchants.enchantments.EcoEnchants
|
||||
import org.bukkit.enchantments.Enchantment
|
||||
import xyz.alexcrea.cuanvil.api.EnchantmentApi
|
||||
import xyz.alexcrea.cuanvil.enchant.wrapped.CALegacyEcoEnchant
|
||||
|
||||
class LegacyEcoEnchantDependency {
|
||||
|
||||
|
||||
private var ecoEnchantOldEnchantments: MutableSet<EcoEnchant>? = null
|
||||
fun registerEnchantments() {
|
||||
val enchantments = EcoEnchants.values()
|
||||
for (ecoEnchant in enchantments) {
|
||||
ecoEnchant as Enchantment
|
||||
|
||||
EnchantmentApi.unregisterEnchantment(ecoEnchant) // As eco enchants is loaded before custom anvil and register enchantment to registry, we need to unregister old "vanilla" enchant.
|
||||
EnchantmentApi.registerEnchantment(CALegacyEcoEnchant(ecoEnchant, ecoEnchant))
|
||||
}
|
||||
|
||||
ecoEnchantOldEnchantments = HashSet(enchantments)
|
||||
}
|
||||
|
||||
fun handleConfigReload() {
|
||||
// Should not happen in known case.
|
||||
if (this.ecoEnchantOldEnchantments == null) return
|
||||
|
||||
val newEnchantments = EcoEnchants.values()
|
||||
|
||||
// Add new enchantments
|
||||
for (ecoEnchant in newEnchantments)
|
||||
if (!this.ecoEnchantOldEnchantments!!.contains(ecoEnchant))
|
||||
EnchantmentApi.registerEnchantment(CALegacyEcoEnchant(ecoEnchant, ecoEnchant as Enchantment))
|
||||
|
||||
|
||||
// Remove old enchantments that not now currently used
|
||||
this.ecoEnchantOldEnchantments!!.removeAll(newEnchantments)
|
||||
for (oldEnchantment in this.ecoEnchantOldEnchantments!!) {
|
||||
EnchantmentApi.unregisterEnchantment(oldEnchantment as Enchantment)
|
||||
}
|
||||
|
||||
this.ecoEnchantOldEnchantments = HashSet(newEnchantments)
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue