You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 06:56:19 +00:00
Preserve signal origin actor context
This commit is contained in:
+30
-7
@@ -103,30 +103,52 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
|
||||
}
|
||||
LOGGER.debug("[SendSignal] Resolved {} antenna(s), firing signals", resolvedAntennas.size());
|
||||
|
||||
RoomUnit triggeringUser = ctx.event().getOriginActor().orElseGet(() -> ctx.actor().orElse(null));
|
||||
List<RoomUnit> forwardedUsers = WiredSourceUtil.resolveUsersRaw(ctx, this.userForward);
|
||||
List<HabboItem> forwardedFurni = WiredSourceUtil.resolveItemsRaw(ctx, this.furniForward, this.forwardItems);
|
||||
|
||||
RoomUnit defaultUser = forwardedUsers.isEmpty() ? null : forwardedUsers.get(0);
|
||||
Collection<RoomUnit> usersToSend = (signalPerUser && !forwardedUsers.isEmpty())
|
||||
? forwardedUsers
|
||||
: Collections.singletonList(defaultUser);
|
||||
List<RoomUnit> usersToSend;
|
||||
if (signalPerUser) {
|
||||
LinkedHashMap<Integer, RoomUnit> mergedUsers = new LinkedHashMap<>();
|
||||
|
||||
if (triggeringUser != null) {
|
||||
mergedUsers.put(triggeringUser.getId(), triggeringUser);
|
||||
}
|
||||
|
||||
for (RoomUnit forwardedUser : forwardedUsers) {
|
||||
if (forwardedUser == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mergedUsers.put(forwardedUser.getId(), forwardedUser);
|
||||
}
|
||||
|
||||
usersToSend = mergedUsers.isEmpty()
|
||||
? Collections.singletonList(null)
|
||||
: new ArrayList<>(mergedUsers.values());
|
||||
} else {
|
||||
usersToSend = Collections.singletonList(triggeringUser);
|
||||
}
|
||||
|
||||
Collection<HabboItem> furniToSend = !forwardedFurni.isEmpty()
|
||||
? forwardedFurni
|
||||
: Collections.singletonList(null);
|
||||
|
||||
int nextDepth = currentDepth + 1;
|
||||
int signalUserCount = signalPerUser
|
||||
? (int) usersToSend.stream().filter(Objects::nonNull).count()
|
||||
: (!forwardedUsers.isEmpty() ? forwardedUsers.size() : (triggeringUser != null ? 1 : 0));
|
||||
|
||||
for (RoomUnit user : usersToSend) {
|
||||
for (HabboItem sourceItem : furniToSend) {
|
||||
for (HabboItem antenna : resolvedAntennas) {
|
||||
fireSignalAtAntenna(ctx, room, antenna, user, sourceItem, nextDepth);
|
||||
fireSignalAtAntenna(ctx, room, antenna, user, triggeringUser, sourceItem, signalUserCount, nextDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fireSignalAtAntenna(WiredContext ctx, Room room, HabboItem antenna, RoomUnit actor, HabboItem sourceItem, int depth) {
|
||||
private void fireSignalAtAntenna(WiredContext ctx, Room room, HabboItem antenna, RoomUnit actor, RoomUnit originActor, HabboItem sourceItem, int signalUserCount, int depth) {
|
||||
if (antenna == null) return;
|
||||
RoomTile tile = room.getLayout().getTile(antenna.getX(), antenna.getY());
|
||||
if (tile == null) return;
|
||||
@@ -142,12 +164,13 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
|
||||
.tile(tile)
|
||||
.callStackDepth(depth)
|
||||
.signalChannel(signalChannel)
|
||||
.signalUserCount(actor != null ? 1 : 0)
|
||||
.signalUserCount(signalUserCount)
|
||||
.signalFurniCount(sourceItem != null ? 1 : 0)
|
||||
.contextVariableScope(ctx.contextVariables())
|
||||
.triggeredByEffect(true);
|
||||
|
||||
if (actor != null) builder.actor(actor);
|
||||
if (originActor != null) builder.originActor(originActor);
|
||||
if (sourceItem != null) builder.sourceItem(sourceItem);
|
||||
|
||||
boolean result = dispatchSignalEvent(builder.build());
|
||||
|
||||
@@ -163,6 +163,7 @@ public final class WiredEvent {
|
||||
private final Type type;
|
||||
private final Room room;
|
||||
private final RoomUnit actor; // nullable - the user/bot that caused the event
|
||||
private final RoomUnit originActor; // nullable - original user that started the chain, preserved across signals
|
||||
private final HabboItem sourceItem; // nullable - the furniture involved
|
||||
private final RoomTile tile; // nullable - the tile where event occurred
|
||||
private final String text; // nullable - text for say triggers
|
||||
@@ -191,6 +192,7 @@ public final class WiredEvent {
|
||||
this.room = builder.room;
|
||||
this.actor = builder.actor;
|
||||
this.sourceItem = builder.sourceItem;
|
||||
this.originActor = builder.originActor;
|
||||
this.tile = builder.tile;
|
||||
this.text = builder.text;
|
||||
this.targetUnit = builder.targetUnit;
|
||||
@@ -240,6 +242,17 @@ public final class WiredEvent {
|
||||
return Optional.ofNullable(actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original actor that started the current event chain.
|
||||
* For signal events this can differ from {@link #getActor()} when the
|
||||
* signal forwards users one-by-one but still needs to preserve who
|
||||
* originally triggered the chain.
|
||||
* @return optional containing the original actor, or empty if unavailable
|
||||
*/
|
||||
public Optional<RoomUnit> getOriginActor() {
|
||||
return Optional.ofNullable(originActor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source item that was involved in this event.
|
||||
* For example, the furniture that was clicked or stepped on.
|
||||
@@ -407,6 +420,7 @@ public final class WiredEvent {
|
||||
private final Type type;
|
||||
private final Room room;
|
||||
private RoomUnit actor;
|
||||
private RoomUnit originActor;
|
||||
private HabboItem sourceItem;
|
||||
private RoomTile tile;
|
||||
private String text;
|
||||
@@ -447,6 +461,11 @@ public final class WiredEvent {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder originActor(RoomUnit originActor) {
|
||||
this.originActor = originActor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source item involved in this event.
|
||||
* @param sourceItem the habbo item
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
<!doctype html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Wired Send Signal - Flow Attuale</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="bg-slate-950 text-slate-100">
|
||||
<div class="mx-auto max-w-7xl px-6 py-10">
|
||||
<header class="mb-8">
|
||||
<span class="inline-flex rounded-full border border-sky-400/30 bg-sky-500/10 px-3 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-sky-300">
|
||||
Wired · Send Signal
|
||||
</span>
|
||||
<h1 class="mt-4 text-4xl font-black tracking-tight text-white">Schema del flow attuale</h1>
|
||||
<p class="mt-3 max-w-4xl text-sm leading-6 text-slate-300">
|
||||
Questa pagina descrive il comportamento attuale del wired <strong>send signal</strong>, con tutti i casi principali:
|
||||
antenne, utenti, furni, conteggi e combinazioni finali. È pensata da inoltrare così com'è per un controllo del flow.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<section class="mb-8 grid gap-4 md:grid-cols-3">
|
||||
<article class="rounded-2xl border border-slate-800 bg-slate-900/80 p-5 shadow-2xl shadow-black/20">
|
||||
<p class="text-xs font-bold uppercase tracking-[0.2em] text-slate-400">Formula finale</p>
|
||||
<p class="mt-3 text-2xl font-black text-emerald-300">antenne × utenti × furni</p>
|
||||
<p class="mt-2 text-sm leading-6 text-slate-300">
|
||||
Il numero totale di segnali emessi è dato dal prodotto tra antenne valide, rami utente e rami furni.
|
||||
</p>
|
||||
</article>
|
||||
<article class="rounded-2xl border border-slate-800 bg-slate-900/80 p-5 shadow-2xl shadow-black/20">
|
||||
<p class="text-xs font-bold uppercase tracking-[0.2em] text-slate-400">Regola utenti</p>
|
||||
<p class="mt-3 text-sm leading-6 text-slate-300">
|
||||
Con <strong>per ogni utente = disattivo</strong>, il ramo usa sempre l'utente che innesca.
|
||||
Con <strong>per ogni utente = attivo</strong>, il ramo usa l'utente che innesca <em>più</em> gli utenti trovati dalla source.
|
||||
</p>
|
||||
</article>
|
||||
<article class="rounded-2xl border border-slate-800 bg-slate-900/80 p-5 shadow-2xl shadow-black/20">
|
||||
<p class="text-xs font-bold uppercase tracking-[0.2em] text-slate-400">Regola furni</p>
|
||||
<p class="mt-3 text-sm leading-6 text-slate-300">
|
||||
Se la source furni restituisce elementi, il flow attuale apre un ramo per ogni furni.
|
||||
Se non restituisce nulla, viene emesso un solo ramo senza furni allegati.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="mb-8 rounded-2xl border border-slate-800 bg-slate-900/80 p-6 shadow-2xl shadow-black/20">
|
||||
<h2 class="text-2xl font-black text-white">Pseudo flow</h2>
|
||||
<ol class="mt-5 space-y-3 text-sm leading-6 text-slate-200">
|
||||
<li><span class="font-bold text-sky-300">1.</span> Vengono risolte le antenne destinazione.</li>
|
||||
<li><span class="font-bold text-sky-300">2.</span> Restano valide solo le antenne reali; se non ne resta nessuna, il flow si ferma.</li>
|
||||
<li><span class="font-bold text-sky-300">3.</span> Viene preso l'utente che ha innescato, se esiste.</li>
|
||||
<li><span class="font-bold text-sky-300">4.</span> Vengono risolti gli utenti dalla source utenti.</li>
|
||||
<li><span class="font-bold text-sky-300">5.</span> Vengono risolti i furni dalla source furni.</li>
|
||||
<li><span class="font-bold text-sky-300">6.</span> Se “per ogni utente” è attivo, si costruisce una lista unica con:
|
||||
<ul class="mt-2 list-disc space-y-1 pl-6 text-slate-300">
|
||||
<li>sempre l'utente che innesca, se presente;</li>
|
||||
<li>poi tutti gli utenti della source;</li>
|
||||
<li>senza duplicati.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><span class="font-bold text-sky-300">7.</span> Se “per ogni utente” è disattivo, si usa un solo ramo utente:
|
||||
l'utente che innesca.</li>
|
||||
<li><span class="font-bold text-sky-300">8.</span> Se la source furni ha elementi, si apre un ramo per ogni furni.</li>
|
||||
<li><span class="font-bold text-sky-300">9.</span> Se la source furni è vuota, si apre un solo ramo senza furni.</li>
|
||||
<li><span class="font-bold text-sky-300">10.</span> Per ogni combinazione antenna + utente + furni viene emesso un segnale separato.</li>
|
||||
<li><span class="font-bold text-sky-300">11.</span> Ogni segnale porta con sé:
|
||||
<ul class="mt-2 list-disc space-y-1 pl-6 text-slate-300">
|
||||
<li>la tile dell'antenna;</li>
|
||||
<li>l'utente del ramo corrente, se presente;</li>
|
||||
<li>l'utente originario che ha innescato la chain, se presente;</li>
|
||||
<li>il furni del ramo corrente, se presente;</li>
|
||||
<li>le context variables;</li>
|
||||
<li>la profondità della chain aggiornata;</li>
|
||||
<li>i conteggi utenti/furni esposti al ramo ricevente.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section class="mb-8 grid gap-6 xl:grid-cols-2">
|
||||
<article class="rounded-2xl border border-slate-800 bg-slate-900/80 p-6 shadow-2xl shadow-black/20">
|
||||
<h2 class="text-2xl font-black text-white">Tabella casi · Utenti</h2>
|
||||
<div class="mt-5 overflow-hidden rounded-xl border border-slate-800">
|
||||
<table class="min-w-full divide-y divide-slate-800 text-sm">
|
||||
<thead class="bg-slate-800/70 text-left text-slate-200">
|
||||
<tr>
|
||||
<th class="px-4 py-3 font-bold">Per ogni utente</th>
|
||||
<th class="px-4 py-3 font-bold">Utente che innesca</th>
|
||||
<th class="px-4 py-3 font-bold">Source utenti</th>
|
||||
<th class="px-4 py-3 font-bold">Rami utente emessi</th>
|
||||
<th class="px-4 py-3 font-bold">Nota</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-800 bg-slate-900/60 text-slate-300">
|
||||
<tr>
|
||||
<td class="px-4 py-3">Disattivo</td>
|
||||
<td class="px-4 py-3">Presente</td>
|
||||
<td class="px-4 py-3">Vuota</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">Parte sempre con l'utente che innesca.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Disattivo</td>
|
||||
<td class="px-4 py-3">Presente</td>
|
||||
<td class="px-4 py-3">3 utenti</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">Gli utenti source non diventano rami separati.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Disattivo</td>
|
||||
<td class="px-4 py-3">Assente</td>
|
||||
<td class="px-4 py-3">Vuota</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">Parte un ramo senza utente.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Attivo</td>
|
||||
<td class="px-4 py-3">Presente</td>
|
||||
<td class="px-4 py-3">Vuota</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">L'utente che innesca viene sempre incluso.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Attivo</td>
|
||||
<td class="px-4 py-3">Presente</td>
|
||||
<td class="px-4 py-3">3 utenti diversi</td>
|
||||
<td class="px-4 py-3">4</td>
|
||||
<td class="px-4 py-3">Utente che innesca + 3 utenti della source.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Attivo</td>
|
||||
<td class="px-4 py-3">Presente</td>
|
||||
<td class="px-4 py-3">Contiene già l'utente che innesca</td>
|
||||
<td class="px-4 py-3">Utenti unici</td>
|
||||
<td class="px-4 py-3">Nessun duplicato.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Attivo</td>
|
||||
<td class="px-4 py-3">Assente</td>
|
||||
<td class="px-4 py-3">3 utenti</td>
|
||||
<td class="px-4 py-3">3</td>
|
||||
<td class="px-4 py-3">Usa solo gli utenti trovati dalla source.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Attivo</td>
|
||||
<td class="px-4 py-3">Assente</td>
|
||||
<td class="px-4 py-3">Vuota</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">Parte un ramo senza utente.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="rounded-2xl border border-slate-800 bg-slate-900/80 p-6 shadow-2xl shadow-black/20">
|
||||
<h2 class="text-2xl font-black text-white">Tabella casi · Furni</h2>
|
||||
<div class="mt-5 overflow-hidden rounded-xl border border-slate-800">
|
||||
<table class="min-w-full divide-y divide-slate-800 text-sm">
|
||||
<thead class="bg-slate-800/70 text-left text-slate-200">
|
||||
<tr>
|
||||
<th class="px-4 py-3 font-bold">Source furni</th>
|
||||
<th class="px-4 py-3 font-bold">Furni trovati</th>
|
||||
<th class="px-4 py-3 font-bold">Rami furni emessi</th>
|
||||
<th class="px-4 py-3 font-bold">Dato nel singolo ramo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-800 bg-slate-900/60 text-slate-300">
|
||||
<tr>
|
||||
<td class="px-4 py-3">Vuota</td>
|
||||
<td class="px-4 py-3">0</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">Nessun furni allegato</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">1 furni</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">Quel furni</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">3 furni</td>
|
||||
<td class="px-4 py-3">3</td>
|
||||
<td class="px-4 py-3">3</td>
|
||||
<td class="px-4 py-3">Un furni diverso per ramo</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">7 furni</td>
|
||||
<td class="px-4 py-3">7</td>
|
||||
<td class="px-4 py-3">7</td>
|
||||
<td class="px-4 py-3">Un furni diverso per ramo</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="mt-4 text-sm leading-6 text-slate-300">
|
||||
Nel comportamento attuale, se la source furni restituisce elementi, il flow si apre sempre per furni singolo.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="mb-8 rounded-2xl border border-slate-800 bg-slate-900/80 p-6 shadow-2xl shadow-black/20">
|
||||
<h2 class="text-2xl font-black text-white">Tabella casi · Combinazioni complete</h2>
|
||||
<div class="mt-5 overflow-hidden rounded-xl border border-slate-800">
|
||||
<table class="min-w-full divide-y divide-slate-800 text-sm">
|
||||
<thead class="bg-slate-800/70 text-left text-slate-200">
|
||||
<tr>
|
||||
<th class="px-4 py-3 font-bold">Caso</th>
|
||||
<th class="px-4 py-3 font-bold">Antenne</th>
|
||||
<th class="px-4 py-3 font-bold">Rami utente</th>
|
||||
<th class="px-4 py-3 font-bold">Rami furni</th>
|
||||
<th class="px-4 py-3 font-bold">Totale segnali</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-800 bg-slate-900/60 text-slate-300">
|
||||
<tr>
|
||||
<td class="px-4 py-3">Utente che innesca presente, per ogni utente disattivo, 3 furni</td>
|
||||
<td class="px-4 py-3">2</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">3</td>
|
||||
<td class="px-4 py-3 font-bold text-emerald-300">6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Utente che innesca presente, per ogni utente attivo, source utenti con 3 utenti, 3 furni</td>
|
||||
<td class="px-4 py-3">2</td>
|
||||
<td class="px-4 py-3">4</td>
|
||||
<td class="px-4 py-3">3</td>
|
||||
<td class="px-4 py-3 font-bold text-emerald-300">24</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Utente che innesca presente, selector utenti vuoto, 7 furni</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">7</td>
|
||||
<td class="px-4 py-3 font-bold text-emerald-300">7</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Nessun utente, source utenti vuota, 7 furni</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">1</td>
|
||||
<td class="px-4 py-3">7</td>
|
||||
<td class="px-4 py-3 font-bold text-emerald-300">7</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3">Nessuna antenna valida</td>
|
||||
<td class="px-4 py-3">0</td>
|
||||
<td class="px-4 py-3">qualsiasi</td>
|
||||
<td class="px-4 py-3">qualsiasi</td>
|
||||
<td class="px-4 py-3 font-bold text-rose-300">0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mb-8 grid gap-6 xl:grid-cols-2">
|
||||
<article class="rounded-2xl border border-slate-800 bg-slate-900/80 p-6 shadow-2xl shadow-black/20">
|
||||
<h2 class="text-2xl font-black text-white">Conteggi esposti al ricevente</h2>
|
||||
<ul class="mt-5 space-y-3 text-sm leading-6 text-slate-300">
|
||||
<li><strong class="text-white">Conteggio utenti con “per ogni utente” attivo:</strong> numero di utenti unici del merge tra utente che innesca e source utenti.</li>
|
||||
<li><strong class="text-white">Conteggio utenti con “per ogni utente” disattivo:</strong> se la source utenti ha elementi, vale il numero di utenti trovati dalla source; altrimenti vale 1 se esiste l'utente che innesca, altrimenti 0.</li>
|
||||
<li><strong class="text-white">Conteggio furni:</strong> nel singolo ramo vale 1 se c'è un furni allegato, altrimenti 0.</li>
|
||||
</ul>
|
||||
</article>
|
||||
<article class="rounded-2xl border border-amber-500/30 bg-amber-500/10 p-6 shadow-2xl shadow-black/20">
|
||||
<h2 class="text-2xl font-black text-amber-200">Nota importante sul comportamento attuale</h2>
|
||||
<p class="mt-5 text-sm leading-6 text-amber-50/90">
|
||||
Oggi il flow reale fa fan-out per furni quando la source furni restituisce elementi. Quindi, se dalla source arrivano 7 furni,
|
||||
il sistema apre 7 rami furni distinti. Questo è importante perché impatta sia il numero totale dei segnali sia i conteggi
|
||||
osservati a valle.
|
||||
</p>
|
||||
<p class="mt-4 text-sm leading-6 text-amber-50/90">
|
||||
Inoltre il segnale conserva anche l'utente originario che ha avviato la chain, separato dall'utente del ramo corrente.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<footer class="border-t border-slate-800 pt-6 text-xs leading-6 text-slate-400">
|
||||
File creato per documentare il flow attuale del wired send signal in modo leggibile e inoltrabile.
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user