Better Javadoc for beginners
This commit is contained in:
parent
0f8ae7923d
commit
075229ab10
@ -15,71 +15,20 @@
|
||||
*/
|
||||
package org.jboss.netty.channel;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
|
||||
/**
|
||||
* Handles or intercepts a downstream {@link ChannelEvent}, and sends a
|
||||
* {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}.
|
||||
*
|
||||
* <h3>Downstream events</h3>
|
||||
* <p>
|
||||
* A downstream event is an event which is supposed to be processed by
|
||||
* a series of downstream handlers in the {@link ChannelPipeline}. It is often
|
||||
* an I/O request made by a user application.
|
||||
* <p>
|
||||
* The most common use case of this interface is to intercept an I/O request
|
||||
* such as {@link Channel#write(Object)} and {@link Channel#close()}. The
|
||||
* received {@link ChannelEvent} object is interpreted as described in the
|
||||
* following table:
|
||||
* such as {@link Channel#write(Object)} and {@link Channel#close()}.
|
||||
*
|
||||
* <table border="1" cellspacing="0" cellpadding="6">
|
||||
* <tr>
|
||||
* <th>Event name</th><th>Event type and condition</th><th>Meaning</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "write"}</td>
|
||||
* <td>{@link MessageEvent}</td><td>Send a message to the {@link Channel}.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "bind"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#BOUND BOUND}, value = {@link SocketAddress})</td>
|
||||
* <td>Bind the {@link Channel} to the specified local address.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "unbind"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#BOUND BOUND}, value = {@code null})</td>
|
||||
* <td>Unbind the {@link Channel} from the current local address.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "connect"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@link SocketAddress})</td>
|
||||
* <td>Connect the {@link Channel} to the specified remote address.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "disconnect"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@code null})</td>
|
||||
* <td>Disconnect the {@link Channel} from the current remote address.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "close"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#OPEN OPEN}, value = {@code false})</td>
|
||||
* <td>Close the {@link Channel}.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <h3>{@link SimpleChannelDownstreamHandler}</h3>
|
||||
* <p>
|
||||
* Other event types and conditions which were not addressed here will be
|
||||
* ignored and discarded. Please note that there's no {@code "open"} in the
|
||||
* table. It is because a {@link Channel} is always open when it is created
|
||||
* by a {@link ChannelFactory}.
|
||||
*
|
||||
* <h4>Additional resources worth reading</h4>
|
||||
* <p>
|
||||
* You might want to refer to {@link ChannelUpstreamHandler} to see how a
|
||||
* {@link ChannelEvent} is interpreted when going upstream. Also, please refer
|
||||
* to the {@link ChannelEvent} and {@link ChannelPipeline} documentation to find
|
||||
* out what an upstream event and a downstream event are, what fundamental
|
||||
* differences they have, and how they flow in a pipeline.
|
||||
* In most cases, you will get to use a {@link SimpleChannelDownstreamHandler}
|
||||
* to implement a downstream handler because it provides an individual handler
|
||||
* method for each event type. You might want to implement this interface
|
||||
* directly though if you want to handle various types of events in more
|
||||
* generic way.
|
||||
*
|
||||
* <h3>Firing an event to the next handler</h3>
|
||||
* <p>
|
||||
|
@ -15,13 +15,19 @@
|
||||
*/
|
||||
package org.jboss.netty.channel;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.channel.socket.ServerSocketChannel;
|
||||
|
||||
/**
|
||||
* An I/O event or I/O request associated with a {@link Channel}.
|
||||
* <p>
|
||||
* A {@link ChannelEvent} is supposed to be handled by the
|
||||
* {@link ChannelPipeline} which is attached to the {@link Channel} that
|
||||
* the event belongs to. Once an event is sent to a {@link ChannelPipeline},
|
||||
* it is handled by a list of {@link ChannelHandler}s.
|
||||
* A {@link ChannelEvent} is handled by a series of {@link ChannelHandler}s in
|
||||
* a {@link ChannelPipeline}.
|
||||
*
|
||||
* <h3>Upstream events and downstream events, and their interpretation</h3>
|
||||
* <p>
|
||||
@ -33,22 +39,142 @@ package org.jboss.netty.channel;
|
||||
* downstream event and say <strong>"an event goes downstream."</strong>
|
||||
* (Please refer to the diagram in {@link ChannelPipeline} for more explanation.)
|
||||
* <p>
|
||||
* A {@link ChannelEvent} is interpreted differently by a {@link ChannelHandler}
|
||||
* depending on whether the event is an upstream event or a downstream event.
|
||||
* An upstream event represents the notification of what happened in the past.
|
||||
* By contrast, a downstream event represents the request of what should happen
|
||||
* in the future. For example, a {@link MessageEvent} represents the
|
||||
* notification of a received message when it goes upstream, while it
|
||||
* represents the request of writing a message when it goes downstream.
|
||||
* When your server receives a message from a client, the event associated with
|
||||
* the received message is an upstream event. When your server sends a message
|
||||
* or reply to the client, the event associated with the write request is a
|
||||
* downstream event. The same rule applies for the client side. If your client
|
||||
* sent a request to the server, it means your client triggered a downstream
|
||||
* event. If your client received a response from the server, it means
|
||||
* your client will be notified with an upstream event. Upstream events are
|
||||
* often the result of inbound operations such as {@link InputStream#read(byte[])},
|
||||
* and downstream events are the request for outbound operations such as
|
||||
* {@link OutputStream#write(byte[])}, {@link Socket#connect(SocketAddress)},
|
||||
* and {@link Socket#close()}.
|
||||
*
|
||||
* <h4>Additional resources worth reading</h4>
|
||||
* <h4>Upstream events</h4>
|
||||
*
|
||||
* <table border="1" cellspacing="0" cellpadding="6">
|
||||
* <tr>
|
||||
* <th>Event name</th></th><th>Event type and condition</th><th>Meaning</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "messageReceived"}</td>
|
||||
* <td>{@link MessageEvent}</td>
|
||||
* <td>a message object (e.g. {@link ChannelBuffer}) was received from a remote peer</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "exceptionCaught"}</td>
|
||||
* <td>{@link ExceptionEvent}</td>
|
||||
* <td>an exception was raised by an I/O thread or a {@link ChannelHandler}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelOpen"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#OPEN OPEN}, value = {@code true})</td>
|
||||
* <td>a {@link Channel} is open, but not bound nor connected</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelClosed"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#OPEN OPEN}, value = {@code false})</td>
|
||||
* <td>a {@link Channel} was closed and all its related resources were released</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelBound"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#BOUND BOUND}, value = {@link SocketAddress})</td>
|
||||
* <td>a {@link Channel} is open and bound to a local address, but not connected</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelUnbound"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#BOUND BOUND}, value = {@code null})</td>
|
||||
* <td>a {@link Channel} was unbound from the current local address</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelConnected"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@link SocketAddress})</td>
|
||||
* <td>a {@link Channel} is open, bound to a local address, and connected to a remote address</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "writeComplete"}</td>
|
||||
* <td>{@link WriteCompletionEvent}</td>
|
||||
* <td>something has been written to a remote peer</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelDisconnected"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@code null})</td>
|
||||
* <td>a {@link Channel} was disconnected from its remote peer</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelInterestChanged"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#INTEREST_OPS INTEREST_OPS}, no value)</td>
|
||||
* <td>a {@link Channel}'s {@link Channel#getInterestOps() interestOps} was changed</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* Please refer to the documentation of {@link ChannelHandler} and its sub-types
|
||||
* ({@link ChannelUpstreamHandler} for upstream events and
|
||||
* {@link ChannelDownstreamHandler} for downstream events) to find out how
|
||||
* a {@link ChannelEvent} is interpreted depending on the type of the handler
|
||||
* more in detail. Also, please refer to the {@link ChannelPipeline}
|
||||
* documentation to find out how an event flows in a pipeline.
|
||||
* These two additional event types are used only for a parent channel which
|
||||
* can have a child channel (e.g. {@link ServerSocketChannel}).
|
||||
* <p>
|
||||
* <table border="1" cellspacing="0" cellpadding="6">
|
||||
* <tr>
|
||||
* <th>Event name</th><th>Event type and condition</th><th>Meaning</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "childChannelOpen"}</td>
|
||||
* <td>{@link ChildChannelStateEvent}<br/>({@code childChannel.isOpen() = true})</td>
|
||||
* <td>a child {@link Channel} was open (e.g. a server channel accepted a connection.)</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "childChannelClosed"}</td>
|
||||
* <td>{@link ChildChannelStateEvent}<br/>({@code childChannel.isOpen() = false})</td>
|
||||
* <td>a child {@link Channel} was closed (e.g. the accepted connection was closed.)</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <h4>Downstream events</h4>
|
||||
*
|
||||
* <table border="1" cellspacing="0" cellpadding="6">
|
||||
* <tr>
|
||||
* <th>Event name</th><th>Event type and condition</th><th>Meaning</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "write"}</td>
|
||||
* <td>{@link MessageEvent}</td><td>Send a message to the {@link Channel}.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "bind"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#BOUND BOUND}, value = {@link SocketAddress})</td>
|
||||
* <td>Bind the {@link Channel} to the specified local address.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "unbind"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#BOUND BOUND}, value = {@code null})</td>
|
||||
* <td>Unbind the {@link Channel} from the current local address.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "connect"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@link SocketAddress})</td>
|
||||
* <td>Connect the {@link Channel} to the specified remote address.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "disconnect"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@code null})</td>
|
||||
* <td>Disconnect the {@link Channel} from the current remote address.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "close"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#OPEN OPEN}, value = {@code false})</td>
|
||||
* <td>Close the {@link Channel}.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* Other event types and conditions which were not addressed here will be
|
||||
* ignored and discarded. Please note that there's no {@code "open"} in the
|
||||
* table. It is because a {@link Channel} is always open when it is created
|
||||
* by a {@link ChannelFactory}.
|
||||
*
|
||||
* <h3>Additional resources worth reading</h3>
|
||||
* <p>
|
||||
* Please refer to the {@link ChannelHandler} and {@link ChannelPipeline}
|
||||
* documentation to find out how an event flows in a pipeline and how to handle
|
||||
* the event in your application.
|
||||
*
|
||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||
* @author Trustin Lee (trustin@gmail.com)
|
||||
|
@ -81,8 +81,8 @@ import java.util.concurrent.ConcurrentMap;
|
||||
* <p>
|
||||
* Please refer to the {@link ChannelHandler}, {@link ChannelEvent}, and
|
||||
* {@link ChannelPipeline} to find out what a upstream event and a downstream
|
||||
* event are, what fundamental differences they have, and how they flow in a
|
||||
* pipeline.
|
||||
* event are, what fundamental differences they have, how they flow in a
|
||||
* pipeline, and how to handle the event in your application.
|
||||
*
|
||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||
* @author Trustin Lee (trustin@gmail.com)
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.jboss.netty.channel;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@ -87,20 +89,26 @@ import org.jboss.netty.handler.ssl.SslHandler;
|
||||
* +-------------+--------------------------+---------------+
|
||||
* | \|/
|
||||
* +-------------+--------------------------+---------------+
|
||||
* | | | |
|
||||
* | [ Socket.read() ] [ Socket.write() ] |
|
||||
* | |
|
||||
* | Netty Internal I/O Threads (Transport Implementation) |
|
||||
* +--------------------------------------------------------+
|
||||
* </pre>
|
||||
* An upstream event is handled by the upstream handlers in the bottom-up
|
||||
* direction as shown on the left side of the diagram. An upstream handler
|
||||
* usually handles the inbound data received from the I/O thread on the bottom
|
||||
* of the diagram. If an upstream event goes beyond the top upstream handler,
|
||||
* it is discarded silently.
|
||||
* usually handles the inbound data generated by the I/O thread on the bottom
|
||||
* of the diagram. The inbound data is often read from a remote peer via the
|
||||
* actual input operation such as {@link InputStream#read(byte[])}.
|
||||
* If an upstream event goes beyond the top upstream handler, it is discarded
|
||||
* silently.
|
||||
* <p>
|
||||
* A downstream event is handled by the downstream handler in the top-down
|
||||
* direction as shown on the right side of the diagram. A downstream handler
|
||||
* usually generates or transforms the outbound traffic such as write requests.
|
||||
* If a downstream event goes beyond the bottom downstream handler, it is
|
||||
* handled by an I/O thread associated with the {@link Channel}.
|
||||
* handled by an I/O thread associated with the {@link Channel}. The I/O thread
|
||||
* often performs the actual output operation such as {@link OutputStream#write(byte[])}.
|
||||
* <p>
|
||||
* For example, let us assume that we created the following pipeline:
|
||||
* <pre>
|
||||
|
@ -15,11 +15,8 @@
|
||||
*/
|
||||
package org.jboss.netty.channel;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.channel.socket.ServerSocketChannel;
|
||||
import org.jboss.netty.handler.execution.ExecutionHandler;
|
||||
import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
|
||||
|
||||
@ -27,100 +24,14 @@ import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
|
||||
/**
|
||||
* Handles or intercepts an upstream {@link ChannelEvent}, and sends a
|
||||
* {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}.
|
||||
* <p>
|
||||
* The most common use case of this interface is to intercept an I/O event
|
||||
* generated by I/O workers to transform the received messages or execute
|
||||
* the relevant business logic.
|
||||
*
|
||||
* <h3>Upstream events</h3>
|
||||
* <h3>{@link SimpleChannelUpstreamHandler}</h3>
|
||||
* <p>
|
||||
* An upstream event is an event which is supposed to be processed by
|
||||
* a series of upstream handlers in the {@link ChannelPipeline}.
|
||||
* The upstream events are generated by an I/O thread, and they have the
|
||||
* following meaning:
|
||||
* <p>
|
||||
* <table border="1" cellspacing="0" cellpadding="6">
|
||||
* <tr>
|
||||
* <th>Event name</th></th><th>Event type and condition</th><th>Meaning</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "messageReceived"}</td>
|
||||
* <td>{@link MessageEvent}</td>
|
||||
* <td>a message object (e.g. {@link ChannelBuffer}) was received from a remote peer</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "exceptionCaught"}</td>
|
||||
* <td>{@link ExceptionEvent}</td>
|
||||
* <td>an exception was raised by an I/O thread or a {@link ChannelHandler}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelOpen"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#OPEN OPEN}, value = {@code true})</td>
|
||||
* <td>a {@link Channel} is open, but not bound nor connected</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelClosed"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#OPEN OPEN}, value = {@code false})</td>
|
||||
* <td>a {@link Channel} was closed and all its related resources were released</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelBound"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#BOUND BOUND}, value = {@link SocketAddress})</td>
|
||||
* <td>a {@link Channel} is open and bound to a local address, but not connected</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelUnbound"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#BOUND BOUND}, value = {@code null})</td>
|
||||
* <td>a {@link Channel} was unbound from the current local address</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelConnected"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@link SocketAddress})</td>
|
||||
* <td>a {@link Channel} is open, bound to a local address, and connected to a remote address</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "writeComplete"}</td>
|
||||
* <td>{@link WriteCompletionEvent}</td>
|
||||
* <td>something has been written to a remote peer</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelDisconnected"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#CONNECTED CONNECTED}, value = {@code null})</td>
|
||||
* <td>a {@link Channel} was disconnected from its remote peer</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "channelInterestChanged"}</td>
|
||||
* <td>{@link ChannelStateEvent}<br/>(state = {@link ChannelState#INTEREST_OPS INTEREST_OPS}, no value)</td>
|
||||
* <td>a {@link Channel}'s {@link Channel#getInterestOps() interestOps} was changed</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* These two additional event types are used only for a parent channel which
|
||||
* can have a child channel (e.g. {@link ServerSocketChannel}).
|
||||
* <p>
|
||||
* <table border="1" cellspacing="0" cellpadding="6">
|
||||
* <tr>
|
||||
* <th>Event name</th><th>Event type and condition</th><th>Meaning</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "childChannelOpen"}</td>
|
||||
* <td>{@link ChildChannelStateEvent}<br/>({@code childChannel.isOpen() = true})</td>
|
||||
* <td>a child {@link Channel} was open (e.g. a server channel accepted a connection.)</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code "childChannelClosed"}</td>
|
||||
* <td>{@link ChildChannelStateEvent}<br/>({@code childChannel.isOpen() = false})</td>
|
||||
* <td>a child {@link Channel} was closed (e.g. the accepted connection was closed.)</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <h4>Additional resources worth reading</h4>
|
||||
* <p>
|
||||
* You might want to refer to {@link ChannelDownstreamHandler} to see how a
|
||||
* {@link ChannelEvent} is interpreted when going downstream. Also, please
|
||||
* refer to the {@link ChannelEvent} and {@link ChannelPipeline} documentation
|
||||
* to find out what an upstream event and a downstream event are, what
|
||||
* fundamental differences they have, and how they flow in a pipeline.
|
||||
*
|
||||
* <h3>{@link SimpleChannelHandler}</h3>
|
||||
* <p>
|
||||
* In most cases, you will get to use a {@link SimpleChannelHandler} to
|
||||
* In most cases, you will get to use a {@link SimpleChannelUpstreamHandler} to
|
||||
* implement an upstream handler because it provides an individual handler
|
||||
* method for each event type. You might want to implement this interface
|
||||
* directly though if you want to handle various types of events in more
|
||||
|
Loading…
x
Reference in New Issue
Block a user