Merge pull request #35 from netty/more-examples
Port over more Netty examples
This commit is contained in:
commit
374b0524d8
@ -2,7 +2,7 @@
|
|||||||
FROM fedora:33
|
FROM fedora:33
|
||||||
RUN dnf -y install file findutils unzip zip libXtst-devel libXt-devel libXrender-devel libXrandr-devel \
|
RUN dnf -y install file findutils unzip zip libXtst-devel libXt-devel libXrender-devel libXrandr-devel \
|
||||||
libXi-devel cups-devel fontconfig-devel alsa-lib-devel make autoconf diffutils git clang \
|
libXi-devel cups-devel fontconfig-devel alsa-lib-devel make autoconf diffutils git clang \
|
||||||
java-latest-openjdk-devel
|
java-latest-openjdk-devel automake libtool
|
||||||
|
|
||||||
# Build panama-foreign openjdk
|
# Build panama-foreign openjdk
|
||||||
WORKDIR /home/build
|
WORKDIR /home/build
|
||||||
@ -24,7 +24,7 @@ ENV PATH=/home/build/apache-maven-3.6.3/bin:$PATH
|
|||||||
# Prepare a snapshot of Netty 5
|
# Prepare a snapshot of Netty 5
|
||||||
RUN git clone -b master https://github.com/netty/netty.git netty
|
RUN git clone -b master https://github.com/netty/netty.git netty
|
||||||
WORKDIR /home/build/netty
|
WORKDIR /home/build/netty
|
||||||
RUN mvn install -DskipTests -T1C -B -am -pl buffer,handler
|
RUN mvn install -DskipTests -T1C -B -am
|
||||||
WORKDIR /home/build
|
WORKDIR /home/build
|
||||||
|
|
||||||
# Prepare our own build
|
# Prepare our own build
|
||||||
|
13
pom.xml
13
pom.xml
@ -394,12 +394,25 @@
|
|||||||
<version>${netty.build.version}</version>
|
<version>${netty.build.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-buffer</artifactId>
|
||||||
|
<version>${netty.version}</version>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-handler</artifactId>
|
<artifactId>netty-handler</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-codec-http</artifactId>
|
||||||
|
<version>${netty.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjdk.jmh</groupId>
|
<groupId>org.openjdk.jmh</groupId>
|
||||||
<artifactId>jmh-core</artifactId>
|
<artifactId>jmh-core</artifactId>
|
||||||
|
@ -877,7 +877,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte getByte(int roff) {
|
public byte getByte(int roff) {
|
||||||
return prepRead(roff, Byte.BYTES).getByte(subOffset);
|
return prepGet(roff, Byte.BYTES).getByte(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -887,7 +887,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getUnsignedByte(int roff) {
|
public int getUnsignedByte(int roff) {
|
||||||
return prepRead(roff, Byte.BYTES).getUnsignedByte(subOffset);
|
return prepGet(roff, Byte.BYTES).getUnsignedByte(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -921,7 +921,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char getChar(int roff) {
|
public char getChar(int roff) {
|
||||||
return prepRead(roff, 2).getChar(subOffset);
|
return prepGet(roff, 2).getChar(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -943,7 +943,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short getShort(int roff) {
|
public short getShort(int roff) {
|
||||||
return prepRead(roff, Short.BYTES).getShort(subOffset);
|
return prepGet(roff, Short.BYTES).getShort(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -953,7 +953,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getUnsignedShort(int roff) {
|
public int getUnsignedShort(int roff) {
|
||||||
return prepRead(roff, Short.BYTES).getUnsignedShort(subOffset);
|
return prepGet(roff, Short.BYTES).getUnsignedShort(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -987,7 +987,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMedium(int roff) {
|
public int getMedium(int roff) {
|
||||||
return prepRead(roff, 3).getMedium(subOffset);
|
return prepGet(roff, 3).getMedium(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -997,7 +997,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getUnsignedMedium(int roff) {
|
public int getUnsignedMedium(int roff) {
|
||||||
return prepRead(roff, 3).getMedium(subOffset);
|
return prepGet(roff, 3).getMedium(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1031,7 +1031,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getInt(int roff) {
|
public int getInt(int roff) {
|
||||||
return prepRead(roff, Integer.BYTES).getInt(subOffset);
|
return prepGet(roff, Integer.BYTES).getInt(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1041,7 +1041,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getUnsignedInt(int roff) {
|
public long getUnsignedInt(int roff) {
|
||||||
return prepRead(roff, Integer.BYTES).getUnsignedInt(subOffset);
|
return prepGet(roff, Integer.BYTES).getUnsignedInt(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1075,7 +1075,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getFloat(int roff) {
|
public float getFloat(int roff) {
|
||||||
return prepRead(roff, Float.BYTES).getFloat(subOffset);
|
return prepGet(roff, Float.BYTES).getFloat(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1097,7 +1097,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLong(int roff) {
|
public long getLong(int roff) {
|
||||||
return prepRead(roff, Long.BYTES).getLong(subOffset);
|
return prepGet(roff, Long.BYTES).getLong(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1119,7 +1119,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getDouble(int roff) {
|
public double getDouble(int roff) {
|
||||||
return prepRead(roff, Double.BYTES).getDouble(subOffset);
|
return prepGet(roff, Double.BYTES).getDouble(subOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1242,6 +1242,17 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BufferAccessors prepGet(int index, int size) {
|
||||||
|
checkGetBounds(index, size);
|
||||||
|
return chooseBuffer(index, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkGetBounds(int index, int size) {
|
||||||
|
if (index < 0 || capacity < index + size) {
|
||||||
|
throw indexOutOfBounds(index, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private BufferAccessors prepWrite(int size) {
|
private BufferAccessors prepWrite(int size) {
|
||||||
var buf = prepWrite(woff, size);
|
var buf = prepWrite(woff, size);
|
||||||
woff += size;
|
woff += size;
|
||||||
@ -1268,7 +1279,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
}
|
}
|
||||||
return new IndexOutOfBoundsException(
|
return new IndexOutOfBoundsException(
|
||||||
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
||||||
(capacity - 1) + "].");
|
capacity + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IllegalStateException bufferIsClosed() {
|
private static IllegalStateException bufferIsClosed() {
|
||||||
|
@ -83,11 +83,13 @@ abstract class LifecycleTracer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addTrace(Trace trace) {
|
void addTrace(Trace trace) {
|
||||||
|
synchronized (traces) {
|
||||||
if (traces.size() == MAX_TRACE_POINTS) {
|
if (traces.size() == MAX_TRACE_POINTS) {
|
||||||
traces.pollFirst();
|
traces.pollFirst();
|
||||||
}
|
}
|
||||||
traces.addLast(trace);
|
traces.addLast(trace);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void drop(int acquires) {
|
void drop(int acquires) {
|
||||||
@ -118,10 +120,12 @@ abstract class LifecycleTracer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
<E extends Throwable> E attachTrace(E throwable) {
|
<E extends Throwable> E attachTrace(E throwable) {
|
||||||
|
synchronized (traces) {
|
||||||
long timestamp = System.nanoTime();
|
long timestamp = System.nanoTime();
|
||||||
for (Trace trace : traces) {
|
for (Trace trace : traces) {
|
||||||
trace.attach(throwable, timestamp);
|
trace.attach(throwable, timestamp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return throwable;
|
return throwable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,8 @@ import io.netty.buffer.ByteBufAllocator;
|
|||||||
import io.netty.buffer.CompositeByteBuf;
|
import io.netty.buffer.CompositeByteBuf;
|
||||||
import io.netty.buffer.api.BufferAllocator;
|
import io.netty.buffer.api.BufferAllocator;
|
||||||
|
|
||||||
|
import static java.nio.ByteOrder.BIG_ENDIAN;
|
||||||
|
|
||||||
public class ByteBufAllocatorAdaptor implements ByteBufAllocator, AutoCloseable {
|
public class ByteBufAllocatorAdaptor implements ByteBufAllocator, AutoCloseable {
|
||||||
private final BufferAllocator onheap;
|
private final BufferAllocator onheap;
|
||||||
private final BufferAllocator offheap;
|
private final BufferAllocator offheap;
|
||||||
@ -53,7 +55,7 @@ public class ByteBufAllocatorAdaptor implements ByteBufAllocator, AutoCloseable
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf buffer(int initialCapacity) {
|
public ByteBuf buffer(int initialCapacity) {
|
||||||
return new ByteBufAdaptor(this, onheap.allocate(initialCapacity));
|
return new ByteBufAdaptor(this, onheap.allocate(initialCapacity).order(BIG_ENDIAN));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -98,9 +100,7 @@ public class ByteBufAllocatorAdaptor implements ByteBufAllocator, AutoCloseable
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf directBuffer(int initialCapacity) {
|
public ByteBuf directBuffer(int initialCapacity) {
|
||||||
// TODO we cannot use off-heap buffers here, until the JDK allows direct byte buffers based on native
|
return new ByteBufAdaptor(this, offheap.allocate(initialCapacity).order(BIG_ENDIAN));
|
||||||
// memory segments to be used in IO operations.
|
|
||||||
return new ByteBufAdaptor(this, onheap.allocate(initialCapacity));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -133,7 +133,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Buffer fill(byte value) {
|
public Buffer fill(byte value) {
|
||||||
checkWrite(0, capacity());
|
checkSet(0, capacity());
|
||||||
seg.fill(value);
|
seg.fill(value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
public void copyInto(int srcPos, Buffer dest, int destPos, int length) {
|
public void copyInto(int srcPos, Buffer dest, int destPos, int length) {
|
||||||
if (dest instanceof MemSegBuffer) {
|
if (dest instanceof MemSegBuffer) {
|
||||||
var memSegBuf = (MemSegBuffer) dest;
|
var memSegBuf = (MemSegBuffer) dest;
|
||||||
memSegBuf.checkWrite(destPos, length);
|
memSegBuf.checkSet(destPos, length);
|
||||||
copyInto(srcPos, memSegBuf.seg, destPos, length);
|
copyInto(srcPos, memSegBuf.seg, destPos, length);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -589,7 +589,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte getByte(int roff) {
|
public byte getByte(int roff) {
|
||||||
checkRead(roff, Byte.BYTES);
|
checkGet(roff, Byte.BYTES);
|
||||||
return getByteAtOffset(seg, roff);
|
return getByteAtOffset(seg, roff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,7 +603,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getUnsignedByte(int roff) {
|
public int getUnsignedByte(int roff) {
|
||||||
checkRead(roff, Byte.BYTES);
|
checkGet(roff, Byte.BYTES);
|
||||||
return getByteAtOffset(seg, roff) & 0xFF;
|
return getByteAtOffset(seg, roff) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,7 +659,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char getChar(int roff) {
|
public char getChar(int roff) {
|
||||||
checkRead(roff, 2);
|
checkGet(roff, 2);
|
||||||
return getCharAtOffset(seg, roff, order);
|
return getCharAtOffset(seg, roff, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,7 +694,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short getShort(int roff) {
|
public short getShort(int roff) {
|
||||||
checkRead(roff, Short.BYTES);
|
checkGet(roff, Short.BYTES);
|
||||||
return getShortAtOffset(seg, roff, order);
|
return getShortAtOffset(seg, roff, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,7 +708,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getUnsignedShort(int roff) {
|
public int getUnsignedShort(int roff) {
|
||||||
checkRead(roff, Short.BYTES);
|
checkGet(roff, Short.BYTES);
|
||||||
return getShortAtOffset(seg, roff, order) & 0xFFFF;
|
return getShortAtOffset(seg, roff, order) & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,7 +770,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMedium(int roff) {
|
public int getMedium(int roff) {
|
||||||
checkRead(roff, 3);
|
checkGet(roff, 3);
|
||||||
return order == ByteOrder.BIG_ENDIAN?
|
return order == ByteOrder.BIG_ENDIAN?
|
||||||
getByteAtOffset(seg, roff) << 16 |
|
getByteAtOffset(seg, roff) << 16 |
|
||||||
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
||||||
@ -796,7 +796,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getUnsignedMedium(int roff) {
|
public int getUnsignedMedium(int roff) {
|
||||||
checkRead(roff, 3);
|
checkGet(roff, 3);
|
||||||
return order == ByteOrder.BIG_ENDIAN?
|
return order == ByteOrder.BIG_ENDIAN?
|
||||||
(getByteAtOffset(seg, roff) << 16 |
|
(getByteAtOffset(seg, roff) << 16 |
|
||||||
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
(getByteAtOffset(seg, roff + 1) & 0xFF) << 8 |
|
||||||
@ -824,7 +824,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Buffer setMedium(int woff, int value) {
|
public Buffer setMedium(int woff, int value) {
|
||||||
checkWrite(woff, 3);
|
checkSet(woff, 3);
|
||||||
if (order == ByteOrder.BIG_ENDIAN) {
|
if (order == ByteOrder.BIG_ENDIAN) {
|
||||||
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
||||||
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
@ -855,7 +855,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Buffer setUnsignedMedium(int woff, int value) {
|
public Buffer setUnsignedMedium(int woff, int value) {
|
||||||
checkWrite(woff, 3);
|
checkSet(woff, 3);
|
||||||
if (order == ByteOrder.BIG_ENDIAN) {
|
if (order == ByteOrder.BIG_ENDIAN) {
|
||||||
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
setByteAtOffset(wseg, woff, (byte) (value >> 16));
|
||||||
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
setByteAtOffset(wseg, woff + 1, (byte) (value >> 8 & 0xFF));
|
||||||
@ -878,7 +878,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getInt(int roff) {
|
public int getInt(int roff) {
|
||||||
checkRead(roff, Integer.BYTES);
|
checkGet(roff, Integer.BYTES);
|
||||||
return getIntAtOffset(seg, roff, order);
|
return getIntAtOffset(seg, roff, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -892,7 +892,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getUnsignedInt(int roff) {
|
public long getUnsignedInt(int roff) {
|
||||||
checkRead(roff, Integer.BYTES);
|
checkGet(roff, Integer.BYTES);
|
||||||
return getIntAtOffset(seg, roff, order) & 0xFFFFFFFFL;
|
return getIntAtOffset(seg, roff, order) & 0xFFFFFFFFL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,7 +948,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getFloat(int roff) {
|
public float getFloat(int roff) {
|
||||||
checkRead(roff, Float.BYTES);
|
checkGet(roff, Float.BYTES);
|
||||||
return getFloatAtOffset(seg, roff, order);
|
return getFloatAtOffset(seg, roff, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -983,7 +983,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLong(int roff) {
|
public long getLong(int roff) {
|
||||||
checkRead(roff, Long.BYTES);
|
checkGet(roff, Long.BYTES);
|
||||||
return getLongAtOffset(seg, roff, order);
|
return getLongAtOffset(seg, roff, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1018,7 +1018,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getDouble(int roff) {
|
public double getDouble(int roff) {
|
||||||
checkRead(roff, Double.BYTES);
|
checkGet(roff, Double.BYTES);
|
||||||
return getDoubleAtOffset(seg, roff, order);
|
return getDoubleAtOffset(seg, roff, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1093,7 +1093,19 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkGet(int index, int size) {
|
||||||
|
if (index < 0 || seg.byteSize() < index + size) {
|
||||||
|
throw readAccessCheckException(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void checkWrite(int index, int size) {
|
private void checkWrite(int index, int size) {
|
||||||
|
if (index < roff || wseg.byteSize() < index + size) {
|
||||||
|
throw writeAccessCheckException(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkSet(int index, int size) {
|
||||||
if (index < 0 || wseg.byteSize() < index + size) {
|
if (index < 0 || wseg.byteSize() < index + size) {
|
||||||
throw writeAccessCheckException(index);
|
throw writeAccessCheckException(index);
|
||||||
}
|
}
|
||||||
@ -1137,7 +1149,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
private IndexOutOfBoundsException outOfBounds(int index) {
|
private IndexOutOfBoundsException outOfBounds(int index) {
|
||||||
return new IndexOutOfBoundsException(
|
return new IndexOutOfBoundsException(
|
||||||
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
||||||
(seg.byteSize() - 1) + "].");
|
seg.byteSize() + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
Object recoverableMemory() {
|
Object recoverableMemory() {
|
||||||
|
File diff suppressed because it is too large
Load Diff
36
src/test/java/io/netty/buffer/api/Memoize.java
Normal file
36
src/test/java/io/netty/buffer/api/Memoize.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
final class Memoize<T> implements Supplier<T> {
|
||||||
|
private final Supplier<T> supplier;
|
||||||
|
private volatile T memo;
|
||||||
|
|
||||||
|
Memoize(Supplier<T> supplier) {
|
||||||
|
this.supplier = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T get() {
|
||||||
|
T val = memo;
|
||||||
|
if (val == null) {
|
||||||
|
memo = val = supplier.get();
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.adaptor;
|
||||||
|
|
||||||
|
import io.netty.buffer.AbstractByteBufTest;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
|
||||||
|
public class ByteBufAdaptorTest extends AbstractByteBufTest {
|
||||||
|
static ByteBufAllocatorAdaptor alloc;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpAllocator() {
|
||||||
|
alloc = new ByteBufAllocatorAdaptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownAllocator() throws Exception {
|
||||||
|
alloc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteBuf newBuffer(int capacity, int maxCapacity) {
|
||||||
|
return alloc.buffer(capacity, capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("New buffers not thread-safe like this.")
|
||||||
|
@Override
|
||||||
|
public void testSliceReadGatheringByteChannelMultipleThreads() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("New buffers not thread-safe like this.")
|
||||||
|
@Override
|
||||||
|
public void testDuplicateReadGatheringByteChannelMultipleThreads() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("New buffers not thread-safe like this.")
|
||||||
|
@Override
|
||||||
|
public void testSliceReadOutputStreamMultipleThreads() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("New buffers not thread-safe like this.")
|
||||||
|
@Override
|
||||||
|
public void testDuplicateReadOutputStreamMultipleThreads() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("New buffers not thread-safe like this.")
|
||||||
|
@Override
|
||||||
|
public void testSliceBytesInArrayMultipleThreads() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("New buffers not thread-safe like this.")
|
||||||
|
@Override
|
||||||
|
public void testDuplicateBytesInArrayMultipleThreads() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This test codifies that asking to reading 0 bytes from an empty but unclosed stream should return -1, " +
|
||||||
|
"which is just weird.")
|
||||||
|
@Override
|
||||||
|
public void testStreamTransfer1() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Relies on capacity and max capacity being separate things.")
|
||||||
|
@Override
|
||||||
|
public void testCapacityIncrease() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Decreasing capacity not supported in new API.")
|
||||||
|
@Override
|
||||||
|
public void testCapacityDecrease() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Decreasing capacity not supported in new API.")
|
||||||
|
@Override
|
||||||
|
public void testCapacityNegative() {
|
||||||
|
throw new IllegalArgumentException(); // Can't ignore tests annotated with throws expectation?
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Decreasing capacity not supported in new API.")
|
||||||
|
@Override
|
||||||
|
public void testCapacityEnforceMaxCapacity() {
|
||||||
|
throw new IllegalArgumentException(); // Can't ignore tests annotated with throws expectation?
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Decreasing capacity not supported in new API.")
|
||||||
|
@Override
|
||||||
|
public void testMaxFastWritableBytes() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Impossible to expose entire memory as a ByteBuffer using new API.")
|
||||||
|
@Override
|
||||||
|
public void testNioBufferExposeOnlyRegion() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Impossible to expose entire memory as a ByteBuffer using new API.")
|
||||||
|
@Override
|
||||||
|
public void testToByteBuffer2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedDuplicateUnreleasable3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedDuplicateUnreleasable4() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedDuplicateAndRetainedSliceContentIsExpected() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testMultipleRetainedSliceReleaseOriginal2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testMultipleRetainedSliceReleaseOriginal3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testMultipleRetainedSliceReleaseOriginal4() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testReadRetainedSliceUnreleasable3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testReadRetainedSliceUnreleasable4() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedSliceUnreleasable3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedSliceUnreleasable4() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedSliceReleaseOriginal2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedSliceReleaseOriginal3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedSliceReleaseOriginal4() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testMultipleRetainedDuplicateReleaseOriginal2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testMultipleRetainedDuplicateReleaseOriginal3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testMultipleRetainedDuplicateReleaseOriginal4() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedDuplicateReleaseOriginal2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedDuplicateReleaseOriginal3() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
||||||
|
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
||||||
|
@Override
|
||||||
|
public void testRetainedDuplicateReleaseOriginal4() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("No longer allowed to allocate 0 sized buffers, except for composite buffers with no components.")
|
||||||
|
@Override
|
||||||
|
public void testLittleEndianWithExpand() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test seems to inherently have double-free bug?")
|
||||||
|
@Override
|
||||||
|
public void testRetainedSliceAfterReleaseRetainedSliceDuplicate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test seems to inherently have double-free bug?")
|
||||||
|
@Override
|
||||||
|
public void testRetainedSliceAfterReleaseRetainedDuplicateSlice() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test seems to inherently have double-free bug?")
|
||||||
|
@Override
|
||||||
|
public void testSliceAfterReleaseRetainedSliceDuplicate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test seems to inherently have double-free bug?")
|
||||||
|
@Override
|
||||||
|
public void testDuplicateAfterReleaseRetainedSliceDuplicate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test seems to inherently have double-free bug?")
|
||||||
|
@Override
|
||||||
|
public void testDuplicateAfterReleaseRetainedDuplicateSlice() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test seems to inherently have double-free bug?")
|
||||||
|
@Override
|
||||||
|
public void testSliceAfterReleaseRetainedDuplicateSlice() {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.snoop;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.MultithreadEventLoopGroup;
|
||||||
|
import io.netty.channel.nio.NioHandler;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||||
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
|
||||||
|
import io.netty.handler.codec.http.cookie.DefaultCookie;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple HTTP client that prints out the content of the HTTP response to
|
||||||
|
* {@link System#out} to test {@link HttpSnoopServer}.
|
||||||
|
*/
|
||||||
|
public final class HttpSnoopClient {
|
||||||
|
|
||||||
|
static final String URL = System.getProperty("url", "http://127.0.0.1:8080/");
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
URI uri = new URI(URL);
|
||||||
|
String scheme = uri.getScheme() == null? "http" : uri.getScheme();
|
||||||
|
String host = uri.getHost() == null? "127.0.0.1" : uri.getHost();
|
||||||
|
int port = uri.getPort();
|
||||||
|
if (port == -1) {
|
||||||
|
if ("http".equalsIgnoreCase(scheme)) {
|
||||||
|
port = 80;
|
||||||
|
} else if ("https".equalsIgnoreCase(scheme)) {
|
||||||
|
port = 443;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) {
|
||||||
|
System.err.println("Only HTTP(S) is supported.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure SSL context if necessary.
|
||||||
|
final boolean ssl = "https".equalsIgnoreCase(scheme);
|
||||||
|
final SslContext sslCtx;
|
||||||
|
if (ssl) {
|
||||||
|
sslCtx = SslContextBuilder.forClient()
|
||||||
|
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
|
||||||
|
} else {
|
||||||
|
sslCtx = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the client.
|
||||||
|
ByteBufAllocatorAdaptor allocator = new ByteBufAllocatorAdaptor();
|
||||||
|
EventLoopGroup group = new MultithreadEventLoopGroup(NioHandler.newFactory());
|
||||||
|
try {
|
||||||
|
Bootstrap b = new Bootstrap();
|
||||||
|
b.group(group)
|
||||||
|
.option(ChannelOption.ALLOCATOR, allocator)
|
||||||
|
.channel(NioSocketChannel.class)
|
||||||
|
.handler(new HttpSnoopClientInitializer(sslCtx, allocator));
|
||||||
|
|
||||||
|
// Make the connection attempt.
|
||||||
|
Channel ch = b.connect(host, port).sync().channel();
|
||||||
|
|
||||||
|
// Prepare the HTTP request.
|
||||||
|
HttpRequest request = new DefaultFullHttpRequest(
|
||||||
|
HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath(), Unpooled.EMPTY_BUFFER);
|
||||||
|
request.headers().set(HttpHeaderNames.HOST, host);
|
||||||
|
request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
|
||||||
|
request.headers().set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
|
||||||
|
|
||||||
|
// Set some example cookies.
|
||||||
|
request.headers().set(
|
||||||
|
HttpHeaderNames.COOKIE,
|
||||||
|
ClientCookieEncoder.STRICT.encode(
|
||||||
|
new DefaultCookie("my-cookie", "foo"),
|
||||||
|
new DefaultCookie("another-cookie", "bar")));
|
||||||
|
|
||||||
|
// Send the HTTP request.
|
||||||
|
ch.writeAndFlush(request);
|
||||||
|
|
||||||
|
// Wait for the server to close the connection.
|
||||||
|
ch.closeFuture().sync();
|
||||||
|
} finally {
|
||||||
|
// Shut down executor threads to exit.
|
||||||
|
group.shutdownGracefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.snoop;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import io.netty.handler.codec.http.HttpContent;
|
||||||
|
import io.netty.handler.codec.http.HttpObject;
|
||||||
|
import io.netty.handler.codec.http.HttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpUtil;
|
||||||
|
import io.netty.handler.codec.http.LastHttpContent;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
public class HttpSnoopClientHandler extends SimpleChannelInboundHandler<HttpObject> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) {
|
||||||
|
if (msg instanceof HttpResponse) {
|
||||||
|
HttpResponse response = (HttpResponse) msg;
|
||||||
|
|
||||||
|
System.err.println("STATUS: " + response.status());
|
||||||
|
System.err.println("VERSION: " + response.protocolVersion());
|
||||||
|
System.err.println();
|
||||||
|
|
||||||
|
if (!response.headers().isEmpty()) {
|
||||||
|
for (CharSequence name: response.headers().names()) {
|
||||||
|
for (CharSequence value: response.headers().getAll(name)) {
|
||||||
|
System.err.println("HEADER: " + name + " = " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.err.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HttpUtil.isTransferEncodingChunked(response)) {
|
||||||
|
System.err.println("CHUNKED CONTENT {");
|
||||||
|
} else {
|
||||||
|
System.err.println("CONTENT {");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (msg instanceof HttpContent) {
|
||||||
|
HttpContent content = (HttpContent) msg;
|
||||||
|
|
||||||
|
System.err.print(content.content().toString(CharsetUtil.UTF_8));
|
||||||
|
System.err.flush();
|
||||||
|
|
||||||
|
if (content instanceof LastHttpContent) {
|
||||||
|
System.err.println("} END OF CONTENT");
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||||
|
cause.printStackTrace();
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.snoop;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.handler.codec.http.HttpClientCodec;
|
||||||
|
import io.netty.handler.codec.http.HttpContentDecompressor;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
|
||||||
|
public class HttpSnoopClientInitializer extends ChannelInitializer<SocketChannel> {
|
||||||
|
|
||||||
|
private final SslContext sslCtx;
|
||||||
|
private final ByteBufAllocator allocator;
|
||||||
|
|
||||||
|
public HttpSnoopClientInitializer(SslContext sslCtx, ByteBufAllocator allocator) {
|
||||||
|
this.sslCtx = sslCtx;
|
||||||
|
this.allocator = allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initChannel(SocketChannel ch) {
|
||||||
|
ChannelPipeline p = ch.pipeline();
|
||||||
|
|
||||||
|
// Enable HTTPS if necessary.
|
||||||
|
if (sslCtx != null) {
|
||||||
|
// `initChannel` runs before the channel options have been applied, so we need to configure
|
||||||
|
// the handler with an allocator that we get passed via the constructor.
|
||||||
|
p.addLast(sslCtx.newHandler(allocator));
|
||||||
|
}
|
||||||
|
|
||||||
|
p.addLast(new HttpClientCodec());
|
||||||
|
|
||||||
|
// Remove the following line if you don't want automatic content decompression.
|
||||||
|
p.addLast(new HttpContentDecompressor());
|
||||||
|
|
||||||
|
// Uncomment the following line if you don't want to handle HttpContents.
|
||||||
|
//p.addLast(new HttpObjectAggregator(1048576));
|
||||||
|
|
||||||
|
p.addLast(new HttpSnoopClientHandler());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.snoop;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.MultithreadEventLoopGroup;
|
||||||
|
import io.netty.channel.nio.NioHandler;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.logging.LogLevel;
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
|
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An HTTP server that sends back the content of the received HTTP request
|
||||||
|
* in a pretty plaintext form.
|
||||||
|
*/
|
||||||
|
public final class HttpSnoopServer {
|
||||||
|
|
||||||
|
static final boolean SSL = System.getProperty("ssl") != null;
|
||||||
|
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// Configure SSL.
|
||||||
|
final SslContext sslCtx;
|
||||||
|
if (SSL) {
|
||||||
|
SelfSignedCertificate ssc = new SelfSignedCertificate();
|
||||||
|
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
|
||||||
|
} else {
|
||||||
|
sslCtx = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the server.
|
||||||
|
ByteBufAllocatorAdaptor allocator = new ByteBufAllocatorAdaptor();
|
||||||
|
EventLoopGroup bossGroup = new MultithreadEventLoopGroup(1, NioHandler.newFactory());
|
||||||
|
EventLoopGroup workerGroup = new MultithreadEventLoopGroup(NioHandler.newFactory());
|
||||||
|
try {
|
||||||
|
ServerBootstrap b = new ServerBootstrap();
|
||||||
|
b.group(bossGroup, workerGroup)
|
||||||
|
.channel(NioServerSocketChannel.class)
|
||||||
|
.childOption(ChannelOption.ALLOCATOR, allocator)
|
||||||
|
.handler(new LoggingHandler(LogLevel.INFO))
|
||||||
|
.childHandler(new HttpSnoopServerInitializer(sslCtx, allocator));
|
||||||
|
|
||||||
|
Channel ch = b.bind(PORT).sync().channel();
|
||||||
|
|
||||||
|
System.err.println("Open your web browser and navigate to " +
|
||||||
|
(SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
|
||||||
|
|
||||||
|
ch.closeFuture().sync();
|
||||||
|
} finally {
|
||||||
|
bossGroup.shutdownGracefully();
|
||||||
|
workerGroup.shutdownGracefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.snoop;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import io.netty.handler.codec.DecoderResult;
|
||||||
|
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.FullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpContent;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
|
import io.netty.handler.codec.http.HttpObject;
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpUtil;
|
||||||
|
import io.netty.handler.codec.http.LastHttpContent;
|
||||||
|
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||||
|
import io.netty.handler.codec.http.cookie.Cookie;
|
||||||
|
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
|
||||||
|
import io.netty.handler.codec.http.cookie.ServerCookieEncoder;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
|
||||||
|
import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
|
||||||
|
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
||||||
|
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||||
|
|
||||||
|
public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object> {
|
||||||
|
|
||||||
|
private HttpRequest request;
|
||||||
|
/** Buffer that stores the response content */
|
||||||
|
private final StringBuilder buf = new StringBuilder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelReadComplete(ChannelHandlerContext ctx) {
|
||||||
|
ctx.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void messageReceived(ChannelHandlerContext ctx, Object msg) {
|
||||||
|
if (msg instanceof HttpRequest) {
|
||||||
|
HttpRequest request = this.request = (HttpRequest) msg;
|
||||||
|
|
||||||
|
if (HttpUtil.is100ContinueExpected(request)) {
|
||||||
|
send100Continue(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.setLength(0);
|
||||||
|
buf.append("WELCOME TO THE WILD WILD WEB SERVER\r\n");
|
||||||
|
buf.append("===================================\r\n");
|
||||||
|
|
||||||
|
buf.append("VERSION: ").append(request.protocolVersion()).append("\r\n");
|
||||||
|
buf.append("HOSTNAME: ").append(request.headers().get(HttpHeaderNames.HOST, "unknown")).append("\r\n");
|
||||||
|
buf.append("REQUEST_URI: ").append(request.uri()).append("\r\n\r\n");
|
||||||
|
|
||||||
|
HttpHeaders headers = request.headers();
|
||||||
|
if (!headers.isEmpty()) {
|
||||||
|
for (Entry<String, String> h: headers) {
|
||||||
|
CharSequence key = h.getKey();
|
||||||
|
CharSequence value = h.getValue();
|
||||||
|
buf.append("HEADER: ").append(key).append(" = ").append(value).append("\r\n");
|
||||||
|
}
|
||||||
|
buf.append("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri());
|
||||||
|
Map<String, List<String>> params = queryStringDecoder.parameters();
|
||||||
|
if (!params.isEmpty()) {
|
||||||
|
for (Entry<String, List<String>> p: params.entrySet()) {
|
||||||
|
String key = p.getKey();
|
||||||
|
List<String> vals = p.getValue();
|
||||||
|
for (String val : vals) {
|
||||||
|
buf.append("PARAM: ").append(key).append(" = ").append(val).append("\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.append("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
appendDecoderResult(buf, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg instanceof HttpContent) {
|
||||||
|
HttpContent httpContent = (HttpContent) msg;
|
||||||
|
|
||||||
|
ByteBuf content = httpContent.content();
|
||||||
|
if (content.isReadable()) {
|
||||||
|
buf.append("CONTENT: ");
|
||||||
|
buf.append(content.toString(CharsetUtil.UTF_8));
|
||||||
|
buf.append("\r\n");
|
||||||
|
appendDecoderResult(buf, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg instanceof LastHttpContent) {
|
||||||
|
buf.append("END OF CONTENT\r\n");
|
||||||
|
|
||||||
|
LastHttpContent trailer = (LastHttpContent) msg;
|
||||||
|
if (!trailer.trailingHeaders().isEmpty()) {
|
||||||
|
buf.append("\r\n");
|
||||||
|
for (CharSequence name: trailer.trailingHeaders().names()) {
|
||||||
|
for (CharSequence value: trailer.trailingHeaders().getAll(name)) {
|
||||||
|
buf.append("TRAILING HEADER: ");
|
||||||
|
buf.append(name).append(" = ").append(value).append("\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.append("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!writeResponse(trailer, ctx)) {
|
||||||
|
// If keep-alive is off, close the connection once the content is fully written.
|
||||||
|
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendDecoderResult(StringBuilder buf, HttpObject o) {
|
||||||
|
DecoderResult result = o.decoderResult();
|
||||||
|
if (result.isSuccess()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.append(".. WITH DECODER FAILURE: ");
|
||||||
|
buf.append(result.cause());
|
||||||
|
buf.append("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean writeResponse(HttpObject currentObj, ChannelHandlerContext ctx) {
|
||||||
|
// Decide whether to close the connection or not.
|
||||||
|
boolean keepAlive = HttpUtil.isKeepAlive(request);
|
||||||
|
// Build the response object.
|
||||||
|
FullHttpResponse response = new DefaultFullHttpResponse(
|
||||||
|
HTTP_1_1, currentObj.decoderResult().isSuccess()? OK : BAD_REQUEST,
|
||||||
|
Unpooled.copiedBuffer(buf.toString(), CharsetUtil.UTF_8));
|
||||||
|
|
||||||
|
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||||
|
|
||||||
|
if (keepAlive) {
|
||||||
|
// Add 'Content-Length' header only for a keep-alive connection.
|
||||||
|
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||||
|
// Add keep alive header as per:
|
||||||
|
// - https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
|
||||||
|
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode the cookie.
|
||||||
|
String cookieString = request.headers().get(HttpHeaderNames.COOKIE);
|
||||||
|
if (cookieString != null) {
|
||||||
|
Set<Cookie> cookies = ServerCookieDecoder.STRICT.decode(cookieString);
|
||||||
|
if (!cookies.isEmpty()) {
|
||||||
|
// Reset the cookies if necessary.
|
||||||
|
for (Cookie cookie: cookies) {
|
||||||
|
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Browser sent no cookie. Add some.
|
||||||
|
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode("key1", "value1"));
|
||||||
|
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode("key2", "value2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the response.
|
||||||
|
ctx.write(response);
|
||||||
|
|
||||||
|
return keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void send100Continue(ChannelHandlerContext ctx) {
|
||||||
|
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, CONTINUE, Unpooled.EMPTY_BUFFER);
|
||||||
|
ctx.write(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||||
|
cause.printStackTrace();
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.snoop;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
|
||||||
|
public class HttpSnoopServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||||
|
|
||||||
|
private final SslContext sslCtx;
|
||||||
|
private final ByteBufAllocator allocator;
|
||||||
|
|
||||||
|
public HttpSnoopServerInitializer(SslContext sslCtx, ByteBufAllocator allocator) {
|
||||||
|
this.sslCtx = sslCtx;
|
||||||
|
this.allocator = allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initChannel(SocketChannel ch) {
|
||||||
|
ChannelPipeline p = ch.pipeline();
|
||||||
|
ch.alloc();
|
||||||
|
if (sslCtx != null) {
|
||||||
|
p.addLast(sslCtx.newHandler(allocator));
|
||||||
|
}
|
||||||
|
p.addLast(new HttpRequestDecoder());
|
||||||
|
// Uncomment the following line if you don't want to handle HttpChunks.
|
||||||
|
//p.addLast(new HttpObjectAggregator(1048576));
|
||||||
|
p.addLast(new HttpResponseEncoder());
|
||||||
|
// Remove the following line if you don't want automatic content compression.
|
||||||
|
//p.addLast(new HttpContentCompressor());
|
||||||
|
p.addLast(new HttpSnoopServerHandler());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,904 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.upload;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.MultithreadEventLoopGroup;
|
||||||
|
import io.netty.channel.nio.NioHandler;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.http.DefaultHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import io.netty.handler.codec.http.QueryStringEncoder;
|
||||||
|
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
|
||||||
|
import io.netty.handler.codec.http.cookie.DefaultCookie;
|
||||||
|
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
|
||||||
|
import io.netty.handler.codec.http.multipart.DiskAttribute;
|
||||||
|
import io.netty.handler.codec.http.multipart.DiskFileUpload;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpDataFactory;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder;
|
||||||
|
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
|
import io.netty.util.internal.SocketUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is meant to be run against {@link HttpUploadServer}.
|
||||||
|
*/
|
||||||
|
public final class HttpUploadClient {
|
||||||
|
|
||||||
|
static final String BASE_URL = System.getProperty("baseUrl", "http://127.0.0.1:8080/");
|
||||||
|
static final String FILE = System.getProperty("file", "README.adoc");
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String postSimple, postFile, get;
|
||||||
|
if (BASE_URL.endsWith("/")) {
|
||||||
|
postSimple = BASE_URL + "formpost";
|
||||||
|
postFile = BASE_URL + "formpostmultipart";
|
||||||
|
get = BASE_URL + "formget";
|
||||||
|
} else {
|
||||||
|
postSimple = BASE_URL + "/formpost";
|
||||||
|
postFile = BASE_URL + "/formpostmultipart";
|
||||||
|
get = BASE_URL + "/formget";
|
||||||
|
}
|
||||||
|
|
||||||
|
URI uriSimple = new URI(postSimple);
|
||||||
|
String scheme = uriSimple.getScheme() == null? "http" : uriSimple.getScheme();
|
||||||
|
String host = uriSimple.getHost() == null? "127.0.0.1" : uriSimple.getHost();
|
||||||
|
int port = uriSimple.getPort();
|
||||||
|
if (port == -1) {
|
||||||
|
if ("http".equalsIgnoreCase(scheme)) {
|
||||||
|
port = 80;
|
||||||
|
} else if ("https".equalsIgnoreCase(scheme)) {
|
||||||
|
port = 443;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) {
|
||||||
|
System.err.println("Only HTTP(S) is supported.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean ssl = "https".equalsIgnoreCase(scheme);
|
||||||
|
final SslContext sslCtx;
|
||||||
|
if (ssl) {
|
||||||
|
sslCtx = SslContextBuilder.forClient()
|
||||||
|
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
|
||||||
|
} else {
|
||||||
|
sslCtx = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
URI uriFile = new URI(postFile);
|
||||||
|
File file = new File(FILE);
|
||||||
|
if (!file.canRead()) {
|
||||||
|
throw new FileNotFoundException(FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the client.
|
||||||
|
ByteBufAllocatorAdaptor allocator = new ByteBufAllocatorAdaptor();
|
||||||
|
EventLoopGroup group = new MultithreadEventLoopGroup(NioHandler.newFactory());
|
||||||
|
|
||||||
|
// setup the factory: here using a mixed memory/disk based on size threshold
|
||||||
|
HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk if MINSIZE exceed
|
||||||
|
|
||||||
|
DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit)
|
||||||
|
DiskFileUpload.baseDirectory = null; // system temp directory
|
||||||
|
DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit)
|
||||||
|
DiskAttribute.baseDirectory = null; // system temp directory
|
||||||
|
|
||||||
|
try {
|
||||||
|
Bootstrap b = new Bootstrap();
|
||||||
|
b.group(group).channel(NioSocketChannel.class)
|
||||||
|
.option(ChannelOption.ALLOCATOR, allocator)
|
||||||
|
.handler(new HttpUploadClientInitializer(sslCtx));
|
||||||
|
|
||||||
|
// Simple Get form: no factory used (not usable)
|
||||||
|
List<Entry<String, String>> headers = formget(b, host, port, get, uriSimple);
|
||||||
|
if (headers == null) {
|
||||||
|
factory.cleanAllHttpData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple Post form: factory used for big attributes
|
||||||
|
List<InterfaceHttpData> bodylist = formpost(b, host, port, uriSimple, file, factory, headers);
|
||||||
|
if (bodylist == null) {
|
||||||
|
factory.cleanAllHttpData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multipart Post form: factory used
|
||||||
|
formpostmultipart(b, host, port, uriFile, factory, headers, bodylist);
|
||||||
|
} finally {
|
||||||
|
// Shut down executor threads to exit.
|
||||||
|
group.shutdownGracefully();
|
||||||
|
|
||||||
|
// Really clean all temporary files if they still exist
|
||||||
|
factory.cleanAllHttpData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard usage of HTTP API in Netty without file Upload (get is not able to achieve File upload
|
||||||
|
* due to limitation on request size).
|
||||||
|
*
|
||||||
|
* @return the list of headers that will be used in every example after
|
||||||
|
**/
|
||||||
|
private static List<Entry<String, String>> formget(
|
||||||
|
Bootstrap bootstrap, String host, int port, String get, URI uriSimple) throws Exception {
|
||||||
|
// XXX /formget
|
||||||
|
// No use of HttpPostRequestEncoder since not a POST
|
||||||
|
Channel channel = bootstrap.connect(host, port).sync().channel();
|
||||||
|
|
||||||
|
// Prepare the HTTP request.
|
||||||
|
QueryStringEncoder encoder = new QueryStringEncoder(get);
|
||||||
|
// add Form attribute
|
||||||
|
encoder.addParam("getform", "GET");
|
||||||
|
encoder.addParam("info", "first value");
|
||||||
|
encoder.addParam("secondinfo", "secondvalue <20><><EFBFBD>&");
|
||||||
|
// not the big one since it is not compatible with GET size
|
||||||
|
// encoder.addParam("thirdinfo", textArea);
|
||||||
|
encoder.addParam("thirdinfo", "third value\r\ntest second line\r\n\r\nnew line\r\n");
|
||||||
|
encoder.addParam("Send", "Send");
|
||||||
|
|
||||||
|
URI uriGet = new URI(encoder.toString());
|
||||||
|
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
|
||||||
|
HttpHeaders headers = request.headers();
|
||||||
|
headers.set(HttpHeaderNames.HOST, host);
|
||||||
|
headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
|
||||||
|
headers.set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP + "," + HttpHeaderValues.DEFLATE);
|
||||||
|
|
||||||
|
headers.set(HttpHeaderNames.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
|
||||||
|
headers.set(HttpHeaderNames.ACCEPT_LANGUAGE, "fr");
|
||||||
|
headers.set(HttpHeaderNames.REFERER, uriSimple.toString());
|
||||||
|
headers.set(HttpHeaderNames.USER_AGENT, "Netty Simple Http Client side");
|
||||||
|
headers.set(HttpHeaderNames.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||||
|
|
||||||
|
//connection will not close but needed
|
||||||
|
// headers.set("Connection","keep-alive");
|
||||||
|
// headers.set("Keep-Alive","300");
|
||||||
|
|
||||||
|
headers.set(
|
||||||
|
HttpHeaderNames.COOKIE, ClientCookieEncoder.STRICT.encode(
|
||||||
|
new DefaultCookie("my-cookie", "foo"),
|
||||||
|
new DefaultCookie("another-cookie", "bar"))
|
||||||
|
);
|
||||||
|
|
||||||
|
// send request
|
||||||
|
channel.writeAndFlush(request);
|
||||||
|
|
||||||
|
// Wait for the server to close the connection.
|
||||||
|
channel.closeFuture().sync();
|
||||||
|
|
||||||
|
// convert headers to list
|
||||||
|
return headers.entries();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard post without multipart but already support on Factory (memory management)
|
||||||
|
*
|
||||||
|
* @return the list of HttpData object (attribute and file) to be reused on next post
|
||||||
|
*/
|
||||||
|
private static List<InterfaceHttpData> formpost(
|
||||||
|
Bootstrap bootstrap,
|
||||||
|
String host, int port, URI uriSimple, File file, HttpDataFactory factory,
|
||||||
|
List<Entry<String, String>> headers) throws Exception {
|
||||||
|
// XXX /formpost
|
||||||
|
// Start the connection attempt.
|
||||||
|
ChannelFuture future = bootstrap.connect(SocketUtils.socketAddress(host, port));
|
||||||
|
// Wait until the connection attempt succeeds or fails.
|
||||||
|
Channel channel = future.sync().channel();
|
||||||
|
|
||||||
|
// Prepare the HTTP request.
|
||||||
|
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString());
|
||||||
|
|
||||||
|
// Use the PostBody encoder
|
||||||
|
HttpPostRequestEncoder bodyRequestEncoder =
|
||||||
|
new HttpPostRequestEncoder(factory, request, false); // false => not multipart
|
||||||
|
|
||||||
|
// it is legal to add directly header or cookie into the request until finalize
|
||||||
|
for (Entry<String, String> entry : headers) {
|
||||||
|
request.headers().set(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add Form attribute
|
||||||
|
bodyRequestEncoder.addBodyAttribute("getform", "POST");
|
||||||
|
bodyRequestEncoder.addBodyAttribute("info", "first value");
|
||||||
|
bodyRequestEncoder.addBodyAttribute("secondinfo", "secondvalue <20><><EFBFBD>&");
|
||||||
|
bodyRequestEncoder.addBodyAttribute("thirdinfo", textArea);
|
||||||
|
bodyRequestEncoder.addBodyAttribute("fourthinfo", textAreaLong);
|
||||||
|
bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false);
|
||||||
|
|
||||||
|
// finalize request
|
||||||
|
request = bodyRequestEncoder.finalizeRequest();
|
||||||
|
|
||||||
|
// Create the bodylist to be reused on the last version with Multipart support
|
||||||
|
List<InterfaceHttpData> bodylist = bodyRequestEncoder.getBodyListAttributes();
|
||||||
|
|
||||||
|
// send request
|
||||||
|
channel.write(request);
|
||||||
|
|
||||||
|
// test if request was chunked and if so, finish the write
|
||||||
|
if (bodyRequestEncoder.isChunked()) { // could do either request.isChunked()
|
||||||
|
// either do it through ChunkedWriteHandler
|
||||||
|
channel.write(bodyRequestEncoder);
|
||||||
|
}
|
||||||
|
channel.flush();
|
||||||
|
|
||||||
|
// Do not clear here since we will reuse the InterfaceHttpData on the next request
|
||||||
|
// for the example (limit action on client side). Take this as a broadcast of the same
|
||||||
|
// request on both Post actions.
|
||||||
|
//
|
||||||
|
// On standard program, it is clearly recommended to clean all files after each request
|
||||||
|
// bodyRequestEncoder.cleanFiles();
|
||||||
|
|
||||||
|
// Wait for the server to close the connection.
|
||||||
|
channel.closeFuture().sync();
|
||||||
|
return bodylist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multipart example
|
||||||
|
*/
|
||||||
|
private static void formpostmultipart(
|
||||||
|
Bootstrap bootstrap, String host, int port, URI uriFile, HttpDataFactory factory,
|
||||||
|
Iterable<Entry<String, String>> headers, List<InterfaceHttpData> bodylist) throws Exception {
|
||||||
|
// XXX /formpostmultipart
|
||||||
|
// Start the connection attempt.
|
||||||
|
ChannelFuture future = bootstrap.connect(SocketUtils.socketAddress(host, port));
|
||||||
|
// Wait until the connection attempt succeeds or fails.
|
||||||
|
Channel channel = future.sync().channel();
|
||||||
|
|
||||||
|
// Prepare the HTTP request.
|
||||||
|
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriFile.toASCIIString());
|
||||||
|
|
||||||
|
// Use the PostBody encoder
|
||||||
|
HttpPostRequestEncoder bodyRequestEncoder =
|
||||||
|
new HttpPostRequestEncoder(factory, request, true); // true => multipart
|
||||||
|
|
||||||
|
// it is legal to add directly header or cookie into the request until finalize
|
||||||
|
for (Entry<String, String> entry : headers) {
|
||||||
|
request.headers().set(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add Form attribute from previous request in formpost()
|
||||||
|
bodyRequestEncoder.setBodyHttpDatas(bodylist);
|
||||||
|
|
||||||
|
// finalize request
|
||||||
|
bodyRequestEncoder.finalizeRequest();
|
||||||
|
|
||||||
|
// send request
|
||||||
|
channel.write(request);
|
||||||
|
|
||||||
|
// test if request was chunked and if so, finish the write
|
||||||
|
if (bodyRequestEncoder.isChunked()) {
|
||||||
|
channel.write(bodyRequestEncoder);
|
||||||
|
}
|
||||||
|
channel.flush();
|
||||||
|
|
||||||
|
// Now no more use of file representation (and list of HttpData)
|
||||||
|
bodyRequestEncoder.cleanFiles();
|
||||||
|
|
||||||
|
// Wait for the server to close the connection.
|
||||||
|
channel.closeFuture().sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// use to simulate a small TEXTAREA field in a form
|
||||||
|
private static final String textArea = "short text";
|
||||||
|
// use to simulate a big TEXTAREA field in a form
|
||||||
|
private static final String textAreaLong =
|
||||||
|
"lkjlkjlKJLKJLKJLKJLJlkj lklkj\r\n\r\nLKJJJJJJJJKKKKKKKKKKKKKKK <20><><EFBFBD><EFBFBD>&\r\n\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" +
|
||||||
|
"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n";
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.upload;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import io.netty.handler.codec.http.HttpContent;
|
||||||
|
import io.netty.handler.codec.http.HttpObject;
|
||||||
|
import io.netty.handler.codec.http.HttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpUtil;
|
||||||
|
import io.netty.handler.codec.http.LastHttpContent;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler that just dumps the contents of the response from the server
|
||||||
|
*/
|
||||||
|
public class HttpUploadClientHandler extends SimpleChannelInboundHandler<HttpObject> {
|
||||||
|
|
||||||
|
private boolean readingChunks;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) {
|
||||||
|
if (msg instanceof HttpResponse) {
|
||||||
|
HttpResponse response = (HttpResponse) msg;
|
||||||
|
|
||||||
|
System.err.println("STATUS: " + response.status());
|
||||||
|
System.err.println("VERSION: " + response.protocolVersion());
|
||||||
|
|
||||||
|
if (!response.headers().isEmpty()) {
|
||||||
|
for (CharSequence name : response.headers().names()) {
|
||||||
|
for (CharSequence value : response.headers().getAll(name)) {
|
||||||
|
System.err.println("HEADER: " + name + " = " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.status().code() == 200 && HttpUtil.isTransferEncodingChunked(response)) {
|
||||||
|
readingChunks = true;
|
||||||
|
System.err.println("CHUNKED CONTENT {");
|
||||||
|
} else {
|
||||||
|
System.err.println("CONTENT {");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (msg instanceof HttpContent) {
|
||||||
|
HttpContent chunk = (HttpContent) msg;
|
||||||
|
System.err.println(chunk.content().toString(CharsetUtil.UTF_8));
|
||||||
|
|
||||||
|
if (chunk instanceof LastHttpContent) {
|
||||||
|
if (readingChunks) {
|
||||||
|
System.err.println("} END OF CHUNKED CONTENT");
|
||||||
|
} else {
|
||||||
|
System.err.println("} END OF CONTENT");
|
||||||
|
}
|
||||||
|
readingChunks = false;
|
||||||
|
} else {
|
||||||
|
System.err.println(chunk.content().toString(CharsetUtil.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||||
|
cause.printStackTrace();
|
||||||
|
ctx.channel().close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.upload;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.handler.codec.http.HttpClientCodec;
|
||||||
|
import io.netty.handler.codec.http.HttpContentDecompressor;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||||
|
|
||||||
|
public class HttpUploadClientInitializer extends ChannelInitializer<SocketChannel> {
|
||||||
|
|
||||||
|
private final SslContext sslCtx;
|
||||||
|
|
||||||
|
public HttpUploadClientInitializer(SslContext sslCtx) {
|
||||||
|
this.sslCtx = sslCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initChannel(SocketChannel ch) {
|
||||||
|
ChannelPipeline pipeline = ch.pipeline();
|
||||||
|
|
||||||
|
if (sslCtx != null) {
|
||||||
|
pipeline.addLast("ssl", sslCtx.newHandler(ch.alloc()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline.addLast("codec", new HttpClientCodec());
|
||||||
|
|
||||||
|
// Remove the following line if you don't want automatic content decompression.
|
||||||
|
pipeline.addLast("inflater", new HttpContentDecompressor());
|
||||||
|
|
||||||
|
// to be used since huge file transfer
|
||||||
|
pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
|
||||||
|
|
||||||
|
pipeline.addLast("handler", new HttpUploadClientHandler());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.upload;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.MultithreadEventLoopGroup;
|
||||||
|
import io.netty.channel.nio.NioHandler;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.logging.LogLevel;
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
|
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An HTTP server showing how to use the HTTP multipart package for file uploads and decoding post data.
|
||||||
|
*/
|
||||||
|
public final class HttpUploadServer {
|
||||||
|
|
||||||
|
static final boolean SSL = System.getProperty("ssl") != null;
|
||||||
|
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// Configure SSL.
|
||||||
|
final SslContext sslCtx;
|
||||||
|
if (SSL) {
|
||||||
|
SelfSignedCertificate ssc = new SelfSignedCertificate();
|
||||||
|
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
|
||||||
|
} else {
|
||||||
|
sslCtx = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBufAllocatorAdaptor allocator = new ByteBufAllocatorAdaptor();
|
||||||
|
EventLoopGroup bossGroup = new MultithreadEventLoopGroup(1, NioHandler.newFactory());
|
||||||
|
EventLoopGroup workerGroup = new MultithreadEventLoopGroup(NioHandler.newFactory());
|
||||||
|
try {
|
||||||
|
ServerBootstrap b = new ServerBootstrap();
|
||||||
|
b.group(bossGroup, workerGroup);
|
||||||
|
b.channel(NioServerSocketChannel.class);
|
||||||
|
b.childOption(ChannelOption.ALLOCATOR, allocator);
|
||||||
|
b.handler(new LoggingHandler(LogLevel.INFO));
|
||||||
|
b.childHandler(new HttpUploadServerInitializer(sslCtx));
|
||||||
|
|
||||||
|
Channel ch = b.bind(PORT).sync().channel();
|
||||||
|
|
||||||
|
System.err.println("Open your web browser and navigate to " +
|
||||||
|
(SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
|
||||||
|
|
||||||
|
ch.closeFuture().sync();
|
||||||
|
} finally {
|
||||||
|
bossGroup.shutdownGracefully();
|
||||||
|
workerGroup.shutdownGracefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,453 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.upload;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.FullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpContent;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||||
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
|
import io.netty.handler.codec.http.HttpObject;
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
|
import io.netty.handler.codec.http.HttpUtil;
|
||||||
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import io.netty.handler.codec.http.LastHttpContent;
|
||||||
|
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||||
|
import io.netty.handler.codec.http.cookie.Cookie;
|
||||||
|
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
|
||||||
|
import io.netty.handler.codec.http.cookie.ServerCookieEncoder;
|
||||||
|
import io.netty.handler.codec.http.multipart.Attribute;
|
||||||
|
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
|
||||||
|
import io.netty.handler.codec.http.multipart.DiskAttribute;
|
||||||
|
import io.netty.handler.codec.http.multipart.DiskFileUpload;
|
||||||
|
import io.netty.handler.codec.http.multipart.FileUpload;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpData;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpDataFactory;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
|
||||||
|
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
|
||||||
|
import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static io.netty.buffer.Unpooled.copiedBuffer;
|
||||||
|
|
||||||
|
public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObject> {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(HttpUploadServerHandler.class.getName());
|
||||||
|
|
||||||
|
private HttpRequest request;
|
||||||
|
|
||||||
|
private HttpData partialContent;
|
||||||
|
|
||||||
|
private final StringBuilder responseContent = new StringBuilder();
|
||||||
|
|
||||||
|
private static final HttpDataFactory factory =
|
||||||
|
new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk if size exceed
|
||||||
|
|
||||||
|
private HttpPostRequestDecoder decoder;
|
||||||
|
|
||||||
|
static {
|
||||||
|
DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file
|
||||||
|
// on exit (in normal
|
||||||
|
// exit)
|
||||||
|
DiskFileUpload.baseDirectory = null; // system temp directory
|
||||||
|
DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on
|
||||||
|
// exit (in normal exit)
|
||||||
|
DiskAttribute.baseDirectory = null; // system temp directory
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
if (decoder != null) {
|
||||||
|
decoder.cleanFiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
|
||||||
|
if (msg instanceof HttpRequest) {
|
||||||
|
HttpRequest request = this.request = (HttpRequest) msg;
|
||||||
|
URI uri = new URI(request.uri());
|
||||||
|
if (!uri.getPath().startsWith("/form")) {
|
||||||
|
// Write Menu
|
||||||
|
writeMenu(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
responseContent.setLength(0);
|
||||||
|
responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n");
|
||||||
|
responseContent.append("===================================\r\n");
|
||||||
|
|
||||||
|
responseContent.append("VERSION: " + request.protocolVersion().text() + "\r\n");
|
||||||
|
|
||||||
|
responseContent.append("REQUEST_URI: " + request.uri() + "\r\n\r\n");
|
||||||
|
responseContent.append("\r\n\r\n");
|
||||||
|
|
||||||
|
// new getMethod
|
||||||
|
for (Entry<String, String> entry : request.headers()) {
|
||||||
|
responseContent.append("HEADER: " + entry.getKey() + '=' + entry.getValue() + "\r\n");
|
||||||
|
}
|
||||||
|
responseContent.append("\r\n\r\n");
|
||||||
|
|
||||||
|
// new getMethod
|
||||||
|
Set<Cookie> cookies;
|
||||||
|
String value = request.headers().get(HttpHeaderNames.COOKIE);
|
||||||
|
if (value == null) {
|
||||||
|
cookies = Collections.emptySet();
|
||||||
|
} else {
|
||||||
|
cookies = ServerCookieDecoder.STRICT.decode(value);
|
||||||
|
}
|
||||||
|
for (Cookie cookie : cookies) {
|
||||||
|
responseContent.append("COOKIE: " + cookie + "\r\n");
|
||||||
|
}
|
||||||
|
responseContent.append("\r\n\r\n");
|
||||||
|
|
||||||
|
QueryStringDecoder decoderQuery = new QueryStringDecoder(request.uri());
|
||||||
|
Map<String, List<String>> uriAttributes = decoderQuery.parameters();
|
||||||
|
for (Entry<String, List<String>> attr: uriAttributes.entrySet()) {
|
||||||
|
for (String attrVal: attr.getValue()) {
|
||||||
|
responseContent.append("URI: " + attr.getKey() + '=' + attrVal + "\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
responseContent.append("\r\n\r\n");
|
||||||
|
|
||||||
|
// if GET Method: should not try to create an HttpPostRequestDecoder
|
||||||
|
if (HttpMethod.GET.equals(request.method())) {
|
||||||
|
// GET Method: should not try to create an HttpPostRequestDecoder
|
||||||
|
// So stop here
|
||||||
|
responseContent.append("\r\n\r\nEND OF GET CONTENT\r\n");
|
||||||
|
// Not now: LastHttpContent will be sent writeResponse(ctx.channel());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
decoder = new HttpPostRequestDecoder(factory, request);
|
||||||
|
} catch (ErrorDataDecoderException e1) {
|
||||||
|
logger.log(Level.WARNING, e1.getMessage(), e1);
|
||||||
|
responseContent.append(e1.getMessage());
|
||||||
|
writeResponse(ctx.channel(), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean readingChunks = HttpUtil.isTransferEncodingChunked(request);
|
||||||
|
responseContent.append("Is Chunked: " + readingChunks + "\r\n");
|
||||||
|
responseContent.append("IsMultipart: " + decoder.isMultipart() + "\r\n");
|
||||||
|
if (readingChunks) {
|
||||||
|
// Chunk version
|
||||||
|
responseContent.append("Chunks: ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the decoder was constructed before
|
||||||
|
// if not it handles the form get
|
||||||
|
if (decoder != null) {
|
||||||
|
if (msg instanceof HttpContent) {
|
||||||
|
// New chunk is received
|
||||||
|
HttpContent chunk = (HttpContent) msg;
|
||||||
|
try {
|
||||||
|
decoder.offer(chunk);
|
||||||
|
} catch (ErrorDataDecoderException e1) {
|
||||||
|
logger.log(Level.WARNING, e1.getMessage(), e1);
|
||||||
|
responseContent.append(e1.getMessage());
|
||||||
|
writeResponse(ctx.channel(), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
responseContent.append('o');
|
||||||
|
// example of reading chunk by chunk (minimize memory usage due to
|
||||||
|
// Factory)
|
||||||
|
readHttpDataChunkByChunk();
|
||||||
|
// example of reading only if at the end
|
||||||
|
if (chunk instanceof LastHttpContent) {
|
||||||
|
writeResponse(ctx.channel());
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeResponse(ctx.channel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset() {
|
||||||
|
request = null;
|
||||||
|
|
||||||
|
// destroy the decoder to release all resources
|
||||||
|
decoder.destroy();
|
||||||
|
decoder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example of reading request by chunk and getting values from chunk to chunk
|
||||||
|
*/
|
||||||
|
private void readHttpDataChunkByChunk() {
|
||||||
|
try {
|
||||||
|
while (decoder.hasNext()) {
|
||||||
|
InterfaceHttpData data = decoder.next();
|
||||||
|
if (data != null) {
|
||||||
|
// check if current HttpData is a FileUpload and previously set as partial
|
||||||
|
long length = -1;
|
||||||
|
if (partialContent == data) {
|
||||||
|
logger.info(" 100% (FinalSize: " + (length = partialContent.length()) + ')');
|
||||||
|
partialContent = null;
|
||||||
|
}
|
||||||
|
// new value
|
||||||
|
writeHttpData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check partial decoding for a FileUpload
|
||||||
|
InterfaceHttpData data = decoder.currentPartialHttpData();
|
||||||
|
if (data != null) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
if (partialContent == null) {
|
||||||
|
partialContent = (HttpData) data;
|
||||||
|
if (partialContent instanceof FileUpload) {
|
||||||
|
builder.append("Start FileUpload: ")
|
||||||
|
.append(((FileUpload) partialContent).getFilename()).append(' ');
|
||||||
|
} else {
|
||||||
|
builder.append("Start Attribute: ")
|
||||||
|
.append(partialContent.getName()).append(' ');
|
||||||
|
}
|
||||||
|
builder.append("(DefinedSize: ").append(partialContent.definedLength()).append(')');
|
||||||
|
}
|
||||||
|
if (partialContent.definedLength() > 0) {
|
||||||
|
builder.append(' ').append(partialContent.length() * 100 / partialContent.definedLength())
|
||||||
|
.append("% ");
|
||||||
|
} else {
|
||||||
|
builder.append(' ').append(partialContent.length()).append(' ');
|
||||||
|
}
|
||||||
|
logger.info(builder.toString());
|
||||||
|
}
|
||||||
|
} catch (EndOfDataDecoderException e1) {
|
||||||
|
// end
|
||||||
|
responseContent.append("\r\n\r\nEND OF CONTENT CHUNK BY CHUNK\r\n\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeHttpData(InterfaceHttpData data) {
|
||||||
|
if (data.getHttpDataType() == HttpDataType.Attribute) {
|
||||||
|
Attribute attribute = (Attribute) data;
|
||||||
|
String value;
|
||||||
|
try {
|
||||||
|
value = attribute.getValue();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
// Error while reading data from File, only print name and error
|
||||||
|
logger.log(Level.WARNING, e1.getMessage(), e1);
|
||||||
|
responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": "
|
||||||
|
+ attribute.getName() + " Error while reading value: " + e1.getMessage() + "\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value.length() > 100) {
|
||||||
|
responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": "
|
||||||
|
+ attribute.getName() + " data too long\r\n");
|
||||||
|
} else {
|
||||||
|
responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": "
|
||||||
|
+ attribute + "\r\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
responseContent.append("\r\nBODY FileUpload: " + data.getHttpDataType().name() + ": " + data
|
||||||
|
+ "\r\n");
|
||||||
|
if (data.getHttpDataType() == HttpDataType.FileUpload) {
|
||||||
|
FileUpload fileUpload = (FileUpload) data;
|
||||||
|
if (fileUpload.isCompleted()) {
|
||||||
|
if (fileUpload.length() < 10000) {
|
||||||
|
responseContent.append("\tContent of file\r\n");
|
||||||
|
try {
|
||||||
|
responseContent.append(fileUpload.getString(fileUpload.getCharset()));
|
||||||
|
} catch (IOException e1) {
|
||||||
|
// do nothing for the example
|
||||||
|
logger.log(Level.WARNING, e1.getMessage(), e1);
|
||||||
|
}
|
||||||
|
responseContent.append("\r\n");
|
||||||
|
} else {
|
||||||
|
responseContent.append("\tFile too long to be printed out:" + fileUpload.length() + "\r\n");
|
||||||
|
}
|
||||||
|
// fileUpload.isInMemory();// tells if the file is in Memory
|
||||||
|
// or on File
|
||||||
|
// fileUpload.renameTo(dest); // enable to move into another
|
||||||
|
// File dest
|
||||||
|
// decoder.removeFileUploadFromClean(fileUpload); //remove
|
||||||
|
// the File of to delete file
|
||||||
|
} else {
|
||||||
|
responseContent.append("\tFile to be continued but should not!\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeResponse(Channel channel) {
|
||||||
|
writeResponse(channel, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeResponse(Channel channel, boolean forceClose) {
|
||||||
|
// Convert the response content to a ChannelBuffer.
|
||||||
|
ByteBuf buf = copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
|
||||||
|
responseContent.setLength(0);
|
||||||
|
|
||||||
|
// Decide whether to close the connection or not.
|
||||||
|
boolean keepAlive = HttpUtil.isKeepAlive(request) && !forceClose;
|
||||||
|
|
||||||
|
// Build the response object.
|
||||||
|
FullHttpResponse response = new DefaultFullHttpResponse(
|
||||||
|
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
|
||||||
|
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||||
|
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
|
||||||
|
|
||||||
|
if (!keepAlive) {
|
||||||
|
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
|
||||||
|
} else if (request.protocolVersion().equals(HttpVersion.HTTP_1_0)) {
|
||||||
|
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Cookie> cookies;
|
||||||
|
String value = request.headers().get(HttpHeaderNames.COOKIE);
|
||||||
|
if (value == null) {
|
||||||
|
cookies = Collections.emptySet();
|
||||||
|
} else {
|
||||||
|
cookies = ServerCookieDecoder.STRICT.decode(value);
|
||||||
|
}
|
||||||
|
if (!cookies.isEmpty()) {
|
||||||
|
// Reset the cookies if necessary.
|
||||||
|
for (Cookie cookie : cookies) {
|
||||||
|
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write the response.
|
||||||
|
ChannelFuture future = channel.writeAndFlush(response);
|
||||||
|
// Close the connection after the write operation is done if necessary.
|
||||||
|
if (!keepAlive) {
|
||||||
|
future.addListener(ChannelFutureListener.CLOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeMenu(ChannelHandlerContext ctx) {
|
||||||
|
// print several HTML forms
|
||||||
|
// Convert the response content to a ChannelBuffer.
|
||||||
|
responseContent.setLength(0);
|
||||||
|
|
||||||
|
// create Pseudo Menu
|
||||||
|
responseContent.append("<html>");
|
||||||
|
responseContent.append("<head>");
|
||||||
|
responseContent.append("<title>Netty Test Form</title>\r\n");
|
||||||
|
responseContent.append("</head>\r\n");
|
||||||
|
responseContent.append("<body bgcolor=white><style>td{font-size: 12pt;}</style>");
|
||||||
|
|
||||||
|
responseContent.append("<table border=\"0\">");
|
||||||
|
responseContent.append("<tr>");
|
||||||
|
responseContent.append("<td>");
|
||||||
|
responseContent.append("<h1>Netty Test Form</h1>");
|
||||||
|
responseContent.append("Choose one FORM");
|
||||||
|
responseContent.append("</td>");
|
||||||
|
responseContent.append("</tr>");
|
||||||
|
responseContent.append("</table>\r\n");
|
||||||
|
|
||||||
|
// GET
|
||||||
|
responseContent.append("<CENTER>GET FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
responseContent.append("<FORM ACTION=\"/formget\" METHOD=\"GET\">");
|
||||||
|
responseContent.append("<input type=hidden name=getform value=\"GET\">");
|
||||||
|
responseContent.append("<table border=\"0\">");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"info\" size=10></td></tr>");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"secondinfo\" size=20>");
|
||||||
|
responseContent
|
||||||
|
.append("<tr><td>Fill with value: <br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
|
||||||
|
responseContent.append("</td></tr>");
|
||||||
|
responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
|
||||||
|
responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
|
||||||
|
responseContent.append("</table></FORM>\r\n");
|
||||||
|
responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
|
||||||
|
// POST
|
||||||
|
responseContent.append("<CENTER>POST FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
responseContent.append("<FORM ACTION=\"/formpost\" METHOD=\"POST\">");
|
||||||
|
responseContent.append("<input type=hidden name=getform value=\"POST\">");
|
||||||
|
responseContent.append("<table border=\"0\">");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"info\" size=10></td></tr>");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"secondinfo\" size=20>");
|
||||||
|
responseContent
|
||||||
|
.append("<tr><td>Fill with value: <br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
|
||||||
|
responseContent.append("<tr><td>Fill with file (only file name will be transmitted): <br> "
|
||||||
|
+ "<input type=file name=\"myfile\">");
|
||||||
|
responseContent.append("</td></tr>");
|
||||||
|
responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
|
||||||
|
responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
|
||||||
|
responseContent.append("</table></FORM>\r\n");
|
||||||
|
responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
|
||||||
|
// POST with enctype="multipart/form-data"
|
||||||
|
responseContent.append("<CENTER>POST MULTIPART FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
responseContent.append("<FORM ACTION=\"/formpostmultipart\" ENCTYPE=\"multipart/form-data\" METHOD=\"POST\">");
|
||||||
|
responseContent.append("<input type=hidden name=getform value=\"POST\">");
|
||||||
|
responseContent.append("<table border=\"0\">");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"info\" size=10></td></tr>");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"secondinfo\" size=20>");
|
||||||
|
responseContent
|
||||||
|
.append("<tr><td>Fill with value: <br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
|
||||||
|
responseContent.append("<tr><td>Fill with file: <br> <input type=file name=\"myfile\">");
|
||||||
|
responseContent.append("</td></tr>");
|
||||||
|
responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
|
||||||
|
responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
|
||||||
|
responseContent.append("</table></FORM>\r\n");
|
||||||
|
responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
|
||||||
|
responseContent.append("</body>");
|
||||||
|
responseContent.append("</html>");
|
||||||
|
|
||||||
|
ByteBuf buf = copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
|
||||||
|
// Build the response object.
|
||||||
|
FullHttpResponse response = new DefaultFullHttpResponse(
|
||||||
|
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
|
||||||
|
|
||||||
|
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||||
|
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
|
||||||
|
|
||||||
|
// Decide whether to close the connection or not.
|
||||||
|
boolean keepAlive = HttpUtil.isKeepAlive(request);
|
||||||
|
if (!keepAlive) {
|
||||||
|
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
|
||||||
|
} else if (request.protocolVersion().equals(HttpVersion.HTTP_1_0)) {
|
||||||
|
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the response.
|
||||||
|
ChannelFuture future = ctx.channel().writeAndFlush(response);
|
||||||
|
// Close the connection after the write operation is done if necessary.
|
||||||
|
if (!keepAlive) {
|
||||||
|
future.addListener(ChannelFutureListener.CLOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
logger.log(Level.WARNING, responseContent.toString(), cause);
|
||||||
|
ctx.channel().close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer.api.examples.http.upload;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.handler.codec.http.HttpContentCompressor;
|
||||||
|
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
|
|
||||||
|
public class HttpUploadServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||||
|
|
||||||
|
private final SslContext sslCtx;
|
||||||
|
|
||||||
|
public HttpUploadServerInitializer(SslContext sslCtx) {
|
||||||
|
this.sslCtx = sslCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initChannel(SocketChannel ch) {
|
||||||
|
ChannelPipeline pipeline = ch.pipeline();
|
||||||
|
|
||||||
|
if (sslCtx != null) {
|
||||||
|
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline.addLast(new HttpRequestDecoder());
|
||||||
|
pipeline.addLast(new HttpResponseEncoder());
|
||||||
|
|
||||||
|
// Remove the following line if you don't want automatic content compression.
|
||||||
|
pipeline.addLast(new HttpContentCompressor());
|
||||||
|
|
||||||
|
pipeline.addLast(new HttpUploadServerHandler());
|
||||||
|
}
|
||||||
|
}
|
18
src/test/resources/junit-platform.properties
Normal file
18
src/test/resources/junit-platform.properties
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Copyright 2021 The Netty Project
|
||||||
|
#
|
||||||
|
# The Netty Project licenses this file to you under the Apache License,
|
||||||
|
# version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at:
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
junit.jupiter.execution.parallel.enabled = true
|
||||||
|
junit.jupiter.execution.parallel.mode.default = concurrent
|
||||||
|
junit.jupiter.testinstance.lifecycle.default = per_class
|
||||||
|
junit.jupiter.execution.parallel.config.strategy = fixed
|
||||||
|
junit.jupiter.execution.parallel.config.fixed.parallelism = 16
|
Loading…
Reference in New Issue
Block a user