Initial commit

This commit is contained in:
kun1z 2020-10-25 16:42:36 -05:00
parent 2ac69b2799
commit 6a09cd6d72
4 changed files with 386 additions and 1 deletions

View File

@ -1,3 +1,3 @@
# tinypage
A tiny single page http server.
A tiny single-page http server.

295
main.c Executable file
View File

@ -0,0 +1,295 @@
//----------------------------------------------------------------------------------------------------------------------
#include <assert.h>
#include <limits.h>
static_assert(CHAR_BIT == 8, "ERROR: This code requires [char] to be exactly 8 bits.");
//----------------------------------------------------------------------------------------------------------------------
#include <stdint.h>
typedef unsigned int ui; typedef int si;
typedef unsigned char u8; typedef char s8;
typedef uint16_t u16; typedef int16_t s16;
typedef uint32_t u32; typedef int32_t s32;
typedef uint64_t u64; typedef int64_t s64;
typedef __uint128_t u128; typedef __int128_t s128;
typedef float r32; typedef double r64;
//----------------------------------------------------------------------------------------------------------------------
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
//----------------------------------------------------------------------------------------------------------------------
#define ENABLE_OUTPUT 1
#define MAX_LISTEN 100
#define BUFSIZE 65536
//----------------------------------------------------------------------------------------------------------------------
void pump(struct sockaddr_in * const restrict, const si); // network pump
void * map_file(s8 const * const restrict, u64 * restrict const); // utility
void o(s8 const * const restrict, ... ); // utility
//----------------------------------------------------------------------------------------------------------------------
void pump(struct sockaddr_in * const restrict addr, const si sock)
{
errno = 0;
char * const buf = malloc(BUFSIZE);
if (errno || !buf)
{
o("memory could not be allocated!\n");
exit(EXIT_FAILURE);
}
u64 filesize;
s8 const * const restrict webpage = map_file("page.htm", &filesize);
if (!filesize || !webpage)
{
o("page.htm could not be found!\n");
exit(EXIT_FAILURE);
}
while (1)
{
o("socket accepting\n");
socklen_t socklen = sizeof(struct sockaddr_in);
errno = 0;
si client_sock = accept(sock, (struct sockaddr*)addr, &socklen);
if (errno || client_sock == -1)
{
o("accept error: %d (%s)\n", errno, inet_ntoa(addr->sin_addr));
continue;
}
errno = 0;
pid_t pid = fork();
if (errno || pid == -1)
{
o("fork error: %d\n", errno);
close(client_sock);
continue;
}
if (!pid) // child
{
errno = 0;
si res = close(sock);
if (errno || res == -1)
{
o("close error: %d (%s)\n", errno, inet_ntoa(addr->sin_addr));
exit(EXIT_FAILURE);
}
o("client with IP %s connected\n", inet_ntoa(addr->sin_addr));
memset(buf, 0, 12);
errno = 0;
const ssize_t len = recv(client_sock, buf, BUFSIZE, 0);
if (errno || len == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
o("recv timeout: %s\n", inet_ntoa(addr->sin_addr));
}
else
{
o("recv error: %d (%s)\n", errno, inet_ntoa(addr->sin_addr));
}
}
else if (!len)
{
o("orderly close: %s\n", inet_ntoa(addr->sin_addr));
}
else
{
o("recv %u bytes from %s\n", len, inet_ntoa(addr->sin_addr));
if (len < 16384)
{
if (ENABLE_OUTPUT)
{
fwrite(buf, 1, len, stdout);
fflush(stdout);
}
if (!strncasecmp(buf, "get ", 4) && strncasecmp(buf, "get /favicon", 12))
{
o("valid request from %s\n", inet_ntoa(addr->sin_addr));
const u64 header_length = sprintf(buf, "HTTP/1.1 200 OK\nServer: tinypage/1.0\nContent-Length: %"PRIu64"\nConnection: close\nContent-Type: text/html; charset=us-ascii\n\n", filesize);
memcpy(&buf[header_length], webpage, filesize);
const u64 packet_size = header_length + filesize;
errno = 0;
ssize_t sent = send(client_sock, buf, packet_size, 0);
if (errno || sent == -1)
{
o("send error: %d (%s)\n", errno, inet_ntoa(addr->sin_addr));
}
else if (sent == packet_size)
{
o("sent %d bytes to %s\n", sent, inet_ntoa(addr->sin_addr));
}
else
{
o("unkown send error: %s\n", inet_ntoa(addr->sin_addr));
}
}
}
}
close(client_sock);
exit(EXIT_SUCCESS);
}
else // parent
{
close(client_sock);
}
}
}
//----------------------------------------------------------------------------------------------------------------------
si main(si argc, s8 ** argv)
{
o("tinypage v1.0\n");
if (argc != 3)
{
o("example: %s 127.0.0.1 80\n", argv[0]);
return EXIT_FAILURE;
}
struct sockaddr_in addr = { 0 };
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));
addr.sin_addr.s_addr = inet_addr(argv[1]);
errno = 0;
const si sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (errno || sock == -1)
{
o("socket error: %d\n", errno);
return EXIT_FAILURE;
}
o("socket open\n");
// socket & TCP options: You may want to change them!
const si off = 0, on = 1;
const struct linger li = { 1, 5 }; // enabled, 5 seconds before timeout
const struct timeval tv = { 5, 0 }; // send/recv 5 second timeout
// Pack all of our options into structured arrays so we can loop over them:
#define options 5
const si p[options][3] =
{
{ SOL_SOCKET, SO_KEEPALIVE, sizeof(off) },
{ SOL_SOCKET, SO_LINGER, sizeof(li) },
{ IPPROTO_TCP, TCP_NODELAY, sizeof(on) },
{ SOL_SOCKET, SO_RCVTIMEO, sizeof(tv) },
{ SOL_SOCKET, SO_SNDTIMEO, sizeof(tv) },
};
void const * const restrict v[options] = { &off, &li, &on, &tv, &tv };
for (si i=0;i<options;i++)
{
errno = 0;
const si res = setsockopt(sock, p[i][0], p[i][1], v[i], p[i][2]);
if (errno || res == -1)
{
o("setsockopt error: %d\n", errno);
return EXIT_FAILURE;
}
}
#undef options
errno = 0;
si res = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (errno || res == -1)
{
o("bind error: %d", errno);
return EXIT_FAILURE;
}
o("socket bound\n");
errno = 0;
res = listen(sock, MAX_LISTEN);
if (errno || res == -1)
{
o("listen error: %d\n", errno);
return EXIT_FAILURE;
}
o("socket listening\n");
pump(&addr, sock);
__builtin_unreachable();
}
//----------------------------------------------------------------------------------------------------------------------
void o(s8 const * const restrict format, ... )
{
if (ENABLE_OUTPUT)
{
va_list t;
va_start(t, format);
vprintf(format, t);
va_end(t);
fflush(stdout);
}
}
//----------------------------------------------------------------------------------------------------------------------
void * map_file(s8 const * const restrict filename, u64 * const restrict filesize)
{
*filesize = 0;
void * p = 0;
si fd = open(filename, O_RDONLY | O_BINARY);
if (fd >= 0)
{
struct stat s;
if (!fstat(fd, &s))
{
const u64 file_size = s.st_size;
p = mmap(0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p == MAP_FAILED)
{
p = 0;
}
else
{
*filesize = file_size;
}
}
close(fd);
}
return p;
}
//----------------------------------------------------------------------------------------------------------------------

2
make.sh Executable file
View File

@ -0,0 +1,2 @@
#!/usr/bin/bash
gcc main.c -o tinypage -Wall -Werror -Wfatal-errors -O3 -flto -fomit-frame-pointer -march=native -mtune=native

88
page.htm Executable file
View File

@ -0,0 +1,88 @@
<html>
<head>
<title>Computer Stuntman</title>
<meta name="description" content="Computer Stuntman">
<meta name="keywords" content="computer stuntman">
</head>
<body bgcolor=black text=white link=blue vlink=purple alink=red>
<center>
<pre><font size=5 face="Courier New"><a href=https://git.tcp.direct/kuntz/tinypage target=_blank><b>Click here to view the source code to this HTTP server</b></a></font></pre>
<pre><font size=1 face="Courier New">MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNNXKKKKKK0000000KKXXXNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXKOkdolc:;,''.'','........'',:ooclddkOKXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNKOxoc;'......,c;..'c' .........'''........,:coxOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKOdc;.... .........xKkxKO' .......... .xkc:odc. ..... ..';ldOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKkl;'.. ..do..........'dKXXXKxc,.........;lOXXXXo........ .......'cokKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOo:.....cdolkXx'........:dxx0XOoll:........:ox0XXKKkc...........,d; ....':dONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXkc,.........oXXXXKOdc..........:Oc...............lKd,,;:'.......'';dXklcc;.....,lkXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXkc''..........,kXKXXOc,............,................;c............:dOKXXXXOc'.......'cokNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMN0o,...xd........'loc;c0d...............'',,,;;,,,,'''..................,kXKKXx........ ....:x0WMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMXx:..'''lXK:.............,,.....';clodxxxxxxxxxxxxxxxxxxxdddolc:,.........,xo,,ldc..........,..';ckNMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMWKd;...'lk0XXXKOx:...........';ldxxxxxdol:;;,,''.........'',;:clodxxxxdl:,....................l0: ....;xXMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMWKo,.......;0NXNXd'........,cdxkkdoc;,'.'''''..,cl:.'cddl,.'cc:,'....',:coxkxdl;............cdodKXk:;,'...;xNMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMXd;.........lK0dxKo.....':dkkxoc,'.'''''',:ldxl.'xXKd;,dOKKl,:kK0kdl:'.''...';cdkkxl,........'oKXXXX0xl,.....;xNMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMNk;','.......'ll'..;:..'cxOkdc,''''''''';::oKNNNXx,.oKXO:''c0Nk,'oKXXXKkl,.........;lxkko;......lK0OKXo. ........:OWMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMW0c'.,dd'..............:dOko:'''''''''',codkdkNXXXXNO,.l00x;'':xOd,.cOK00Okood:'........'cdOkl,...:;..;xx' ..........lKMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMNx;''',kNklod:'......,oOOd:'''''''''''';oOk0XOkOkOK0O0x;.cOKOd:.:OKO:.;xOxlclkOkd:'.........,ck0x:.......'.............,kNMMMMMMMMMMMMMM
MMMMMMMMMMMMWKl,,:odkKXXN0l'.....;d0Ol;'''''''''''';odOXXX0OOdclk0KXNk'.dXNNk;'oKN0:.cKNK0OOxok0l'...........;d0kc...............c;...,oXMMMMMMMMMMMMM
MMMMMMMMMMMWO:,,,:lokXNXN0c''..;d0kc,'''''''''''''l00dkO0KxxOO0XNNXXNXo.,kNXXd',kXNk,.oXXXXXKkdddko,...........,o0Oc.......cdoccOXc.....;OWMMMMMMMMMMM
MMMMMMMMMMNx;,;,,,;,lK0ooxx:',d0Ol,''''''''''''''oXOox0KOloOXNNNNNXNXNO;.:0NN0c.lKNXo.,kNXXXXNKooO0k;............,d0O:......cKXXXXx:,....'xWMMMMMMMMMM
MMMMMMMMMNd,,,;;;;;,ld:,,',;l00o;','''''''''',''dXN00NXOkO0XNNXNNNNXXNXl.'xNNXd',xNNO;.lXNXKKNXKKKkOOc.............;xKd'...,dKXXXXOxl;....'dNMMMMMMMMM
MMMMMMMMXd;;;;;;;;;;;;,,,,:kKk:,,,,,,''''''''''lXNXNX0xOXNNNOkKNNXkkKNNx'.l0KNO:'lKNXl.,ONXxok0XOkK0kkc'.............c00c..:c::oK0;.........oNMMMMMMMM
MMMMMMMNd;:c;;;;;::;;;;,,l0Ko;,,,,,,,,,'',,,,.:0NXNKxxKNNNNNOokOOOxkXXN0:.;oONKl':ONXo..dNNKxkOOxdKNKkd:'.............;kKd......:d'.........'oNMMMMMMM
MMMMMMNd;;cOklldkd:;;;;;oK0c;;;,,,,,,,,,,,,,''xNNNKdkXNNNNNNXkkKKXkkXNNXl.,;xNXo',xXNx'.oKkkk0XN0x0XXXOo;'.............'oKk,................''dWMMMMMM
MMMMMWx:;;l0NXXNk:;;;;;dXO:;;;;,,,,,,,,,,,,,.;0NN0okNNNNNNNNKkOXNXOxdkKXo'''dXNx,,oXNx'.l0kkOO00kxokXXX0o,.'............'lKO;......''.......'.'xWMMMMM
MMMMWO::ok0XNXNN0dc:;:xXk:;;;;;;,,,,,,,,,,,,'dNN0ldNNNNNNNNKxk0k0kx0KXXNd''.lXNd,,oXNx'.lXNXNOox00kkKNXNO;.''..........'.'lK0;.....;xd:',lo,.'.'0MMMMM
MMMMKl;:clld0N0ddxo::xXk:;:;;;;;;,,,,,,,,,,',OWXlcKNNNNNNNNXXXNXklkNNNNNd,'.lXNd,,lOOl'.cO00XKk0XXXXXXXXXx'.''.....''''''',lKO;.....lXX0KXo...'.:XMMMM
MMMNd;;;::::k0l;::::dXOc::::;;;;;;;;,,,,,,;':KW0:xNNNNNNXKK0OOOOxloxxxkkl,,,cddc:;;;,,''''',:coxOKXXXXXXKOc.'''''''''''''',,oXk,.';oOXXXXXkl,.'..dWMMM
MMM0:;::;::;cl::::;lKKl:::::;;;;;;;;;;;;;;;,lKWkcONNXklc::;;,;clodxxkxddxxO0KKKKKKK000OOkxdoc'..';ldOKKKKOo,.''''''''''''''',xXd'';cclOX0dooc,.'.,0MMM
MMNo;;::;::::::::;cOXd:::::::;;;;;;;;;;;;;;,lXWOckNXd,,,,;cdk0XNNXKOOOOKNNXXXXXXXXXXXXXXXXNNXd'.....,ckOk0x;.'''''''''',,,,,':0Kc.''''cOo......''.oWMM
MM0:;;;::;:::::::;dXOc::::::::;;;;;;;;;;;;:;lXNXdlK0:,:;;dXNNXKOOOO0XNNXXNNNNNNNXXXXNNNNXXXXN0:.''...;xdxK0l'',',,,,,,,,,,,,,,oXO;'''',;,''''''',.,0MM
MWx;col::cxkc;:::c0Xo::::::::::::::::;;;:::;lKNNXxoxxkKOokKOOOOO0OOkOOO00XNNNNNNXXNNNNNNNNNXN0:.'....lKl,dXk,',,,,,,,,,,,,,,,,:OXl''''''''''''''''.dMM
MXl,:kX0OKNk:;:::dXOc::::::::::::::::::::::;c0NNNNKxdk00OkO0KK0kdolooooxOO00KKKXXK0kkxxxxxx0N0:;codo:xO:',dx;',,,,,,,,,,,,,,,,,dNk;'''',:;''''''',.:NM
M0:;;l0NNNNKkdl::kXx:::::::::::::::::::::::::xNNNNNXO0NNNO0X0kxxkxlcclddxKXKKKKNKkdooooodddxKkld0XNKkOd,,,,,,,,,,,,,,,,,,,,,,;,lKKc',,,,d0l,''''',.,0M
Mk;:oO00XNXOddl:c0Ko:c:::::::::::::::::::::c:lKNNNNN0OXNN0OXX0kk0Kkkkkkkk0KXNNNX0kkxxoodxkxk0xoOXXXOkk:,;,,,,,,,,,,,,,,,,,;;;;,:OXo',,,'oXKxldd:',.'kM
Wx;:ccc:oKKl;::;lK0l:c:c::::::::::::::c::ccc:ckNNNNNKOKNNKOXNK0KXNNNNNXK0KNNNNNX0OKKXXXKXNKKKdxXXN0kkl,;;;;,;;;;;;;;,;;;,,;;;;,;kNx,':ldOXXXXKl,''',xM
Nd;;;;:;;oxc;::;oXOc:c:c::::::::::::::ccccccc:oKNNNNXOKNNKkKNNNNNNNNNNNNNXXNNNXN0OXNXXXXXXXNOlONXXkko;;;;;;;;;;;;;;;;;;;;;;;;;;;xNk,,:ldkKXXXKd,'','xM
No,;;;;;;;::;;:;dXOc:c::::::::::::::cccccccccc:xNNNNXO0NN0kXNXNNNNNNK00KXKXNXXXNKOKXKXNXXXXNkdKNXOxo;;;;;;;;;;;;;;;;;;;;;;;;;;;;xNk;,,,':0Xxodxo;''.dM
No,;;;;;;;;;;;:;oXOc:c::ccc:::::cccccccccccccc:ckNNNXO0NNOkK0KNNX000O0KOOKKKO0XNX0OOOOKNXXXNkxXN0dl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;xNk;,,,':xo,''',,''.dM
Nd;;;;;;;coc;::;oX0c:cc:ccc:::ccccccccccccccccc:ckXNKOKNXdd0O0XKOOKXNNNX0000KK0OOOOKX0OOK0KKokN0dc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kNx,,,,,,;,,,''''''.dM
Wx;:cc:;cOXo;::;lKKl:ccccc::cc::cccccccccccccccc:cx0kdxO0xlO0k0KXK0kOKXNNNNNNXKOKNNNXXKO0OOdl00o:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;,:ONd,,,,,,,,,,'''','.xM
Mk;;lxOO0NNOool::OXd:ccc::c:::::::::cc:cc::ccc::cc:::;:ONNdl00OXNNX0xodk000OOOOOO0kdkOKXXKk;,c;,,,;,,,,,;;;,,,,;;;;;;;;;;;;;;;,lKKl',,,,::,,,'''',''kM
MO:;;:xXNNNNKkoc;xNk::c::::::::::::::::::::::::::::::;;dXNXdlOXXNNNNNKdlddddxxxxdddkKNXXN0do:.,,,,,,,,,,,,;,,',,,;;;;;;;;;;;;;;dXO:',,,;kO;'''''',.'OM
MKc;;lOKOOXXd;;;;lKKl:c::::::::::::::::::::::::::::::;cxOO0XOox0NNNNNNX0kdoodxxxdxKNXXXX0xxd,',,,,,,,,,,,,,,,,,,,,,,;;;;;;;;;,:OXd,;coldKXkool:'',.:XM
MNd,;llc;;lOx:;:;:kXx::::::::::::::::::::::::::::::::;lkXKkkXXxlkKXNNNNNX0kkOOkOk0XXXXKOkxkO:.,''''''''',,,,,,,,,,,,,,,,,;;;;,oX0c',cd0XXKXKkl,',,.oWM
MMO:,;;;;;;:c:;;:;lKKl:::::::::::::::::::::::::::::::;oOk0XddXNOoxOKNXXNXK0000000KXXX0kOkkXKl,'''''''''''''''',,,,,,,,,,,,,;,c0Xd,',,'dXXKX0c',',.,OMM
MMXl,;;;;;;;;;;;;;;xNOc::::::::::::::::::::::::::::::;:xxlxxokk00xkOOKNNXNNNNNNNNXXXOxkk0XN0dccc,''''''''''''''''',,,,,,,,,,;kNO;'',':kklcoOx;',,.cNMM
MMWO;,;;;;;;;ll;;;;:OXx::::::::::::::::::::::::::::::;;:oocckX0xkOxkOOOOKXNNNNXNNXKkdxOKNX0dcdl:c,.'''..''.''''''''''',,,,,,dX0c''''';:,',',:;',.'OMMM
MMMNo,;;;;;,c00c,;;;l0Xd::::::::::::::::::::::::::;:coo:cooco0NKocxolOK0O0000OOOkddxO00OkOOko:':Od,.'.........''''''''',,,,oKKl'''''''''','''','.lNMMM
MMMM0:,;coddkXN0xkdc;lKKo::::::::::::::::::::::::;:kOdc:cx0OldKNKxlddoodddolllodl:cdkOkk0XXXX0dcdd;.''..........'''''',,,,lKKo''''':;'''''','''.,0MMMM
MMMMWx;;cdOXNNNNXkc;;;lKXd::::::::::::::::::::::;;dOl,c00kkxo;:oxko;lOkdoodddxkOklclOXNXXXXXXXXKd,.'''...........''''',,,oKKo,'.''l0l'''''''''..xWMMMM
MMMMMNd,;,;kNXKXXx;;;;;l0Xd:::::::::::::::::::::;;::,:0NXNNNXKOxkOOkoxK0OOOOOOOkk0XKxOXXXXXNXXK00d'.'''''........'''''',dKKl',ldodKXo,'''''''..oNMMMMM
MMMMMMXl,,l0OlclxOo;;;;;cOXkc;::::::::::::::::;;;;;;;xX0OOOOOOOKXNXN0:ck0KKKOkk0XXXXKxkXXX0OOOOkkkdol:,'''........'''';kX0c''';xKXXX0Oxo:,'''.cXMMMMMM
MMMMMMMKl,cl;,;;,;:;;;;;;:xX0o::::::::::;;;:;;;;;;;,;xOOO00000O0K0OOOl',;::;,oXNXXXK0kookkO0XNXXXXXXXKOd;.'.......'.'l0Xx;.''''oKXXX0dl:,'''.:XMMMMMMM
MMMMMMMMKl,,;;;;;;;;;;;;;;;l0Xkc;::::::;;;;;;;;;;;;oOXNNXXXXXXXXXXK0kc',,,,,''lkOOkOOkkxkKXXXXXXXXXXNNXNk,.'.......;xK0l'..'''lkxodKO;','''.:KMMMMMMMM
MMMMMMMMMKl,,;,,;;;,:dl;;;;;:dKKd:;:::;;;;;;;;;;;,lKNXXXXXXXXXXXXXXXN0c''''''.,odlxXXXXXXXXXXX0Oxxdxxxxxl'.'.....,o0Kd,......';,'''cx:''''.cXMMMMMMMMM
MMMMMMMMMMXo;,,,,;;,:OXxccodc;ckK0o:;:;;;;;;;;;;,,dNXK0OOkkkkkO0KXNNXNk,''''''.';clkXXNXKOkxxxxxdoodxkkxl'.''..,o0Kk:..,'.....'''''',,''..lXMMMMMMMMMM
MMMMMMMMMMMNx;,,,,;cdKNXKKKx:;;;ckK0dc;;;;;;;;;;,'ckOxdolllccllodxxkkOd,''''''''''.,okkkkkxxkOOOkxdooll:'....;o0Kx:..;x0k:.......'''''...dNMMMMMMMMMMM
MMMMMMMMMMMMWO:,:okKNNXXXN0l;;;;;;cx00xl;;;;;;;,,,,:cccloodxxkkkkxoc:;'.'''......'..:llolc;,;;;:;;'.......'cx0Kd;..,dK0OOc.........''..,OWMMMMMMMMMMMM
MMMMMMMMMMMMMWKo;;:cdKNXKKXKx:;;;;;;:dOKOdc;,;,,,,,''''''',;;;:::;,...''...............................':oOKOl,...:0XXOxkd:oxc'.......lXMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMNk:,,;kNkc:codc;,;;;cc;;cxO0Ooc;,,,,''''''''''''''''''''.............................,:ok0Oo:...:o:':d0XXXxd0X0c.....,kWMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMWKd;;xd;,;,,,,;;;lOKX0kl,;cdO0Oxl:,''''''''''''.................................,:lx00xl,...;:oKX0:..,oOKK00k:.....oXMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMW0o:,,,,,,,,;,c0NX0OXXx;''';ldO0Oxoc;,'''''''.'..........................,;cox00Odc,...,lOKKxoOXO;...'d0kc.....c0WMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMNOl;,,,,,;lkkkKN0kOKk;;ddc,.';coxOOOkxol:;,''..................',;:codkO0Oxo:,...':ol,;d0XKOx0Xk,....,.....cOWMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMNOl;,,,:ONXkxXNKo:,'dXNXxll:'...,:loxkOOOOkkxddddoooooodddxkkOOOOkxol:,.......oKXXXk;.'lOKKKKXk'.......cOWMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMW0d:,,ckKXXNXO:',oKNKddKNKo..;:,.....',::clloooddddddoollc:;,'.....';coddc..oXK00X0o..'ckKKkl'....,o0WMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMWXxc,,coxdl;',oKNKol0NKo'.,OX0Oxoc'..''........................'d0KKO0XXd.'OXOOXXKk:...:;....'cxXWMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOd:,'',,':0NXxo0NKc...cKNKxOXXx.'x0Okkxdl'.;oooodddo:.......:0XKoc0XKc.cKX0xOXKk;....',cdONMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXOo:,'',o0XKXX0c...,kXXOoOXXd.'OXKkxKXO,.cKNXX0OKXK:.......cKX0loKXO,.kXKd:c,..'';lxONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNOdc;',clol,...'dXXK0KXKx,.;0XX0ko:,..,OWXXOkKXO,........oKXOkKXO,.;c,..,;,:dxONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKkdc,......cOKXO:;:;...lXX0xkd;...'kWXKK0KXO,....... ;0KOxoc'...;:coxkOKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNKkdc;'..';c:......,kNXKOKNO,..'kNXXOd0XKo.........,,...,;:ldOO0KNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNKkdlc;'......':cllooxl...,xOkkxloxdc........',,:ldkO0KXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXKOxolc:;'......................,,;cldkkO0KXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNXK0OOkkxxddddoddxkxkOO0KXXNWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM</font></pre>
<pre><font size=7 face="Courier New"><a href=https://git.tcp.direct/kuntz target=_blank><b>https://git.tcp.direct/kuntz</b></a></font></pre>
</center>
</body>
</html>