--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null
+CLIBS = -llua5.4 -lsqlite3 -lm -lpthread -lcrypto -lssl
+CFLAGS = -Wall -Wextra
+CFILES = index.c
+HFILES = file.h net.h file.h parse.h render.h config.h perr.h
+
+index: $(CFILES) $(HFILES)
+ gcc $(CGLAGS) $^ -o $@ $(CLIBS)
+
+debug: index.c
+ gcc $(CGLAGS) -D DEBUG -g $^ -o $@ $(CLIBS)
--- /dev/null
+= Low Level Website
+
+A website made using low level libraries that incorporates ssl through openssl.
+
+== Running
+
+Run index to start the server. It does need to be ran as root so it can connect
+to a web socket. The server will be hosted on https://localhost[]. You also need
+to allow your browser to access the page because it might be considered unsafe
+if you don't have the correct certificate files for openssl. Any html
+inside of the public directory will be rendered.
+
+----
+sudo ./index
+----
+
+== Building
+
+----
+make
+----
--- /dev/null
+/*
+ * Copyright (C) 2024 Austin Larsen
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#define PEMFILE "server.pem"
--- /dev/null
+#!/usr/bin/env bash
+HOSTNAME=nyquistdev.net
+DOCINFODIR=/usr/local/share/readme-to-html
--- /dev/null
+/*
+ * Copyright (C) 2024 Austin Larsen
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef _FILE_H_
+#define _GNU_SOURCE
+#define _FILE_H_
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void readLines(fp, data, callback)
+ // SYNOPSIS:
+ // reads lines from a file descriptor and performs job based on those
+ // lines
+
+ FILE *fp; /* File descriptor */
+ void *data; /* data that can be passed to callback*/
+ void (*callback) /* callback to be called for each line of file*/
+ (char *line, /* string of the current line in the loop */
+ size_t len, /* length of the current line in the loop */
+ void *data, /* passed to callback from readLines */
+ uint32_t linenum);
+{
+ rewind(fp);
+ size_t read;
+ size_t len = 0;
+ uint32_t linenum = 0;
+
+ while(1) {
+ char *line = NULL;
+ read = getline(&line, &len, fp);
+ if (read == (size_t)-1) {free(line); return;}
+ linenum++;
+ callback(line, read, data, linenum);
+ free(line);
+ }
+} // readLines()
+
+#endif // _FILE_H_
--- /dev/null
+HTTP/1.1 200 OK\r
+Connection: close\r
+Content-Type: text/html\r
--- /dev/null
+/*
+ * Copyright (C) 2024 Austin Larsen
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <regex.h>
+#include <lua5.4/lua.h>
+#include <lua5.4/lauxlib.h>
+#include <lua5.4/lualib.h>
+#include <sqlite3.h>
+#include <pthread.h>
+
+#include "render.h"
+
+void handle_posts (char *request, char *message) {
+ printf("YO, HANDLE A POST!\n");
+ printf("handle_posts request:\n%s\n", request);
+ memcpy(message, "<h1>HELLO</h1>\0", sizeof(char) * 14);
+
+}
+
+void htmlRenderCallback(file_path, file_name, linenum)
+ char *file_path;
+ char *file_name;
+ uint32_t linenum;
+{
+ lua_State *L = luaL_newstate();
+ luaL_openlibs(L);
+ if (strcmp(file_name, "index.html")) return;
+
+ Html html;
+ HttpHeader header;
+
+ htmlFile2Header_alloc(&header, "./http_headers/basic");
+
+ htmlFile2Str_alloc(&html, file_path);
+
+ LuaTag luaTag;
+ luaTag_alloc(&luaTag, L);
+ Render render;
+ renderInit(&render, &luaTag, &html, &header);
+
+ readLines(html.fp, &render, getRenderInfoCallback);
+
+
+ lua_pushlightuserdata(L, &html);
+ lua_setglobal(L, "html");
+
+
+ lua_pushcfunction(L, l_tagToStr);
+ lua_setglobal(L, "tagToStr");
+
+ if(luaL_dostring(luaTag.state, luaTag.h_buffer) != LUA_OK) {
+ fprintf(stderr, "[C] error reading lua at\n%s line %d\n",
+ __FILE__, __LINE__);
+ }
+
+ lua_getglobal(luaTag.state, "var");
+
+ /* const char *var = lua_tostring(luaTag.state, -1); */
+ /* printf("var: %s\n", var); */
+
+ /* printf("%s\n", render.h_buffer); */
+ NetServer netServer;
+ netInit(&netServer, PEMFILE);
+ /* netAssign(&netServer, "/", "GET", "<h1>hello!<h1>"); */
+ /* netAssign(&netServer, "/", "GET", render.h_buffer); */
+ netAssign(&netServer, "/next", "GET", "<h1>hello then</h1>");
+ printf("WHAT IS THAT?\n");
+ netAssign(&netServer, "/", "GET", render.h_buffer);
+ netAssign(&netServer, "/", "POST", "<h1>might work</h1>");
+
+ netListen(&netServer, handle_posts);
+ netClose(netServer);
+
+ luaTag_dealloc(&luaTag, L);
+ htmlFile2Str_dealloc(&html);
+ htmlFile2Header_dealloc(&header);
+ renderFree(render);
+} // htmlRenderCallback()
+
+int main(int args, char **argv)
+{
+ searchFileType("./public", "html", htmlRenderCallback);
+ return 0;
+
+} // main()
--- /dev/null
+/*
+ * Copyright (C) 2024 Austin Larsen
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef NET_H
+#define NET_H
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <math.h>
+#include <errno.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "perr.h"
+
+
+typedef struct
+_NetKV
+{
+ char *key;
+ char *value;
+}
+NetKV;
+
+typedef struct _Response
+{
+ char path[128];
+ char method[10];
+ char message[2048];
+} Response;
+
+
+typedef struct
+_NetServer
+{
+ SSL_CTX *ctx;
+ struct addrinfo *bind_address;
+ int socket;
+ char pemFile[32];
+ SSL * ssl;
+ Response *responses;
+ uint8_t reslen;
+}
+NetServer;
+
+typedef void (*post_callback) (char *request, char *message);
+
+void netParse_alloc(out, outlen, netkv, len)
+ char **out;
+ uint16_t *outlen;
+ NetKV *netkv;
+ uint8_t len;
+{
+ *out = NULL;
+ char *outp = NULL;
+ *outlen = 0;
+
+ for (int i = 0; i < len; ++i) {
+ char *key = netkv[i].key;
+ char *value = netkv[i].value;
+ int keylen = strlen(key);
+ int valuelen = strlen(value);
+
+ uint16_t llen = keylen + valuelen + 2;
+ *outlen += llen;
+
+ if (*out == NULL) {
+ *out = malloc(*outlen);
+ outp = *out;
+ } else {
+ *out = realloc(*out, *outlen);
+ }
+
+ memcpy(outp, key, keylen);
+ outp += keylen;
+
+ memcpy(outp, "=", 1);
+ outp += 1;
+
+ memcpy(outp,value, valuelen);
+ outp += valuelen;
+
+ if (i != len - 1) {
+ memcpy(outp, "&", 1);
+ outp += 1;
+ }
+ }
+}
+
+void netAssign(netServer, path, method, message)
+ NetServer *netServer;
+ char *path;
+ char *method;
+ char *message;
+{
+ uint8_t i = netServer->reslen;
+ netServer->reslen++;
+
+ if (i == 0) {
+ netServer->responses = malloc(sizeof(Response));
+ } else {
+ netServer->responses = realloc(netServer->responses,
+ sizeof(Response) * (i + 1));
+ }
+
+ memset(netServer->responses[i].path, 0, sizeof(netServer->responses->path));
+ memset(netServer->responses[i].method, 0,
+ sizeof(netServer->responses[i].method));
+ memset(netServer->responses[i].message, 0,
+ sizeof(netServer->responses[i].message));
+ memcpy(netServer->responses[i].path, path, strlen(path));
+ memcpy(netServer->responses[i].method, method, strlen(method));
+ memcpy(netServer->responses[i].message, message, strlen(message));
+}
+
+int netInit(netServer, pemFile)
+ NetServer *netServer;
+ char *pemFile;
+{
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ SSL_load_error_strings();
+ netServer->reslen = 0;
+
+ memset(netServer->pemFile, 0, 32);
+ memcpy(netServer->pemFile, pemFile, strlen(pemFile));
+
+
+ netServer->ctx = SSL_CTX_new(TLS_server_method());
+ if (!netServer->ctx) {
+ PERROR("SSL_CTX_new() failed");
+ return 1;
+ }
+
+ if (!SSL_CTX_use_certificate_file
+ (netServer->ctx,
+ netServer->pemFile, SSL_FILETYPE_PEM) ||
+ !SSL_CTX_use_PrivateKey_file
+ (netServer->ctx, netServer->pemFile,
+ SSL_FILETYPE_PEM)) {
+ PERROR("SSL_CTX_use_certificate_file() failed");
+ ERR_print_errors_fp(stderr);
+ return 2;
+ }
+
+ printf("Configuring local address...\n");
+
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET; // IPv4
+ hints.ai_socktype = SOCK_STREAM; // TCP
+ hints.ai_flags = AI_PASSIVE;
+
+ /* struct addrinfo *bind_address; */
+ getaddrinfo(0, "443", &hints,
+ &netServer->bind_address);
+
+ printf("Creating socket...\n");
+ netServer->socket = socket(netServer->bind_address->ai_family,
+ netServer->bind_address->ai_socktype,
+ netServer->bind_address->ai_protocol);
+ if (netServer->socket < 0) {
+ PERROR("socket() failed");
+ return 3;
+ }
+ printf("Binding socket to local address...\n");
+
+ if (bind(netServer->socket, netServer->bind_address->ai_addr,
+ netServer->bind_address->ai_addrlen)) {
+ PERROR("bind() failed");
+ return 4;
+ }
+
+ return 0;
+}
+int netListen(netServer, callback)
+ NetServer *netServer;
+ post_callback callback;
+{
+ printf("Listening..\n");
+
+ if (listen(netServer->socket, 10) < 0) {
+ PERROR("listen() failed");
+ return 5;
+ }
+
+ while(1) {
+ printf("Waiting for connection...\n");
+ struct sockaddr_storage client_address;
+ socklen_t client_len = sizeof(client_address) + 1;
+
+ int socket_client = accept(netServer->socket,
+ (struct sockaddr *)&client_address, &client_len);
+
+ if (socket_client < 0) {
+ PERROR("accept() failed");
+ return 1;
+ }
+
+ printf("Client is connected...");
+ char address_buffer[100];
+ getnameinfo((struct sockaddr *)&client_address, client_len,
+ address_buffer, sizeof(address_buffer), 0, 0, NI_NUMERICHOST);
+ printf("%s\n", address_buffer);
+
+ netServer->ssl = SSL_new(netServer->ctx);
+ if (!netServer->ctx) {
+ PERROR("SSL_new() failed");
+ return 1;
+ }
+
+ SSL_set_fd(netServer->ssl, socket_client);
+
+ if (SSL_accept(netServer->ssl) <= 0) {
+ fprintf(stderr, "SSL_accept() failed.\n");
+ ERR_print_errors_fp(stderr);
+
+ SSL_shutdown(netServer->ssl);
+ close(socket_client);
+ SSL_free(netServer->ssl);
+ continue;
+ }
+
+ //printf("SSL connection using %s\n", SSL_get_cipher(netServer->ssl));
+
+ //printf("Reading request...\n");
+ char request[1024];
+ memset(request, 0, 1024);
+ /* int bytes_received = SSL_read(netServer->ssl, request, 1024); */
+ SSL_read(netServer->ssl, request, 1024);
+ /* printf("Received %d bytes.\n", bytes_received); */
+ //printf("request: %s\n", request);
+
+ //printf("=======\n");
+
+ char *dup = strdup(request);
+ char *p = dup;
+ char *line = p;
+ while (*p && *p != '\r') ++p;
+ *p = '\0';
+ //printf("\n'%s'\n", line);
+
+ bool isGet = strstr(line, "GET") != NULL;
+ bool isPost = strstr(line, "POST") != NULL;
+ if (isGet) {
+ p = line += 4;
+ }else if (isPost) {
+ p = line += 5;
+ }
+ char *path = p;
+ while (*p && *p != ' ') ++p;
+ *p = '\0';
+ //printf("path: '%s'\n", path);
+
+ for (int i = 0; i < netServer->reslen; ++i) {
+ if ((!strcmp(netServer->responses[i].method, "GET") && isGet)) {
+ if (!strcmp(netServer->responses[i].path, path)) {
+ //printf("sup\n");
+ /* int bytes_sent = SSL_write(netServer->ssl, */
+ SSL_write(netServer->ssl,
+ netServer->responses[i].message,
+ strlen(netServer->responses[i].message));
+ }
+ }
+ if ((!strcmp(netServer->responses[i].method, "POST") && isPost)) {
+ if (!strcmp(netServer->responses[i].path, path)) {
+ //printf("POST REQUEST!!!\n");
+ char message[2048] = {0};
+ callback(request, message);
+ //char *message = "<h1>hello</h1>\0";
+ SSL_write(netServer->ssl,
+ message,
+ strlen(message));
+ }
+ }
+ }
+
+ SSL_shutdown(netServer->ssl);
+ free(dup);
+ close(socket_client);
+ SSL_free(netServer->ssl);
+ }
+ return 0;
+}
+
+int netClose(netServer)
+ NetServer netServer;
+{
+ free(netServer.responses);
+ close(netServer.socket);
+ SSL_CTX_free(netServer.ctx);
+ return 0;
+}
+#endif // NET_H
--- /dev/null
+== Code layout
+Every function needs a comment. A description of every paramenter and what it
+does
+
+=== Structs
+basic struct layout
+
+----
+typedef struct _HTML
+ // ALLOCATE_FUNCTION: html_file2str_alloc
+ // DEALLOCATED_FUNCTION: html_file2str_dealloc
+{
+ char *path; /* the path of the file provided in the path argument */
+ char *h_buffer; /* heap allocated string of the html file */
+ long size; /* size of @h_buffer */
+ xmlDoc *doc; /* parsed html */
+}
+HTML;
+----
+
+Always include and ALLOCATE_FUNCTION and DEALLOCATED_FUNCTION and describe what
+each attribute is for.
+
+=== Functions
+basic function layout
+
+[source, c]
+----
+void html_file2str_alloc (path, out_html)
+ // SYNOPSIS:
+ // Gets info from a html file.
+ //
+ // It gets the path from @path, reads the file, and then places
+ // information about the file into the @out_html struct
+
+
+ char *path; /* path of the html file */
+
+ HTML *out_html; /* struct the gets allocated with information from the html
+ * file */
+{
+}
+----
+
+Always include a SYNOPSIS. describe each argument. If mentioning an argument put
+a "@" symbol in from of it. Detailed description is always after SYNOPSIS.
+
+=== Function arguments
+these are listed in the order they should be put in
+h_<name>:: function is allocated on the heap and needs to be freed
+out_<name>:: function writes to this buffer
+in_<name>:: function reads from this buffer
+io_<name>:: function reads and write to this buffer
+
+=== Function names
+underscored
+
+<name>_alloc:: there is heap allocation in this function and needs to be follow by a
+`_d` function before the program ends
+
+<name>_dealloc:: there is heap deallocation in this function
+
+=== Curly braces
+Do newline for left cruly brace. Do this so you can put a comment between the
+keyword and the block statement.
+
+put a comment at the end of every right curly brace that is not a struct
+declaration.
+
+=== Nesting
+Do not nest greater then three layers!!
+
+=== Comments
+Always align comments for arguments or attributes in functions, struct, enumns
+and unions so the columns all start at the same point
+
+for example:
+
+[source, c]
+----
+{
+ char *path; /* the path of the file provided in the path argument */
+ char *h_buffer; /* heap allocated string of the html file */
+ long size; /* size of @h_buffer */
+ xmlDoc *doc; /* parsed html */
+}
+----
+
+=== Alphabetize
+Alphabetize all Functions. Use function prototyping so errors do not occur.
+
+order:
+
+1. all capitals
+3. regular
+
+
+=== Includes
+include system librarys before user libraries. seperate them with a space.
+
+== Libraries
+libxml2:: parsing html
+
+== Questions
+Associated arrays in c.
+
+== Links
+- https://en.wikipedia.org/wiki/Programming_language
+- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
+- https://www.tutorialspoint.com/c-program-to-list-all-files-and-sub-directories-in-a-directory
+- https://stackoverflow.com/questions/4553012/checking-if-a-file-is-a-directory-or-just-a-file
+- http://www.lua.org/manual/5.1/manual.html#luaL_checktype
+- https://www.youtube.com/watch?v=It0OFCbbTJE
+- https://www.suse.com/support/kb/doc/?id=000018152
--- /dev/null
+-- https://reqbin.com/Article/HttpGet
--- /dev/null
+/*
+ * Copyright (C) 2024 Austin Larsen
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef _PARSE_H_
+#define _PARSE_H_
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <lua5.4/lua.h>
+#include <lua5.4/lauxlib.h>
+#include <lua5.4/lualib.h>
+#include <regex.h>
+
+#include "file.h"
+
+#define STARTTAG "<lua>"
+#define ENDTAG "</lua>"
+
+typedef struct _HeaderKV
+ // ALLOCATE_FUNCTION: htmlFile2Header_alloc
+ // DEALLOCATED_FUNCTION: htmlFile2Header_dealloc
+ //
+ // Key value pairs for the http header.
+{
+ char key[255];
+ char value[255];
+}
+HeaderKV;
+
+typedef struct _LuaTag
+ // ALLOCATE_FUNCTION: luaTag_alloc
+ // DEALLOCATED_FUNCTION: luaTag_dealloc
+{
+ lua_State *state;
+ bool in_tag;
+ /* char *h_buffer; */
+ /* uint32_t content_len; */
+ char h_buffer[2048];
+ uint32_t lines_count;
+}
+LuaTag;
+
+typedef struct _HttpHeader
+ // ALLOCATE_FUNCTION: htmlFile2Header_alloc
+ // DEALLOCATED_FUNCTION: htmlFile2Header_dealloc
+ //
+ // The values attribute in @h_parsed are not parsed, just the top level key
+ // value pairs
+{
+ FILE *fp;
+ char h_buffer[2048]; /* heap allocated string for the header */
+ HeaderKV *h_parsed; /* heap allocated key value pairs for the header*/
+ uint16_t parsed_size; /* size of the @h_parsed attribute */
+ char protocol[255];
+}
+
+HttpHeader;
+
+typedef struct _Tag
+ // ALLOCATE_FUNCTION:
+ // DEALLOCATED_FUNCTION:
+{
+ char name[10];
+ uint32_t startline;
+ uint32_t endline;
+ regmatch_t start;
+ regmatch_t end;
+}
+Tag;
+
+typedef struct _Html
+ // ALLOCATE_FUNCTION: htmlFile2Str_alloc
+ // DEALLOCATED_FUNCTION: htmlFile2Str_dealloc
+{
+ FILE *fp;
+ HttpHeader header; /* header info for the http */
+ char *path; /* the path of the file provided in the path
+ * argument */
+ char **h_lines;
+ uint32_t lines_count;
+ uint32_t lines_size;
+ Tag *h_tags; /* heap allocated tags, that specify that name of that
+ * tag along with their starting and ending locations */
+ uint16_t tag_count; /* number of h_tags */
+}
+Html;
+
+void allocHeaderKV(out_header, line, len)
+ // SYNOPSIS:
+ // allocates the key value pairs for the http header
+
+ HttpHeader *out_header; /*HttpHeader struct */
+ char *line; /*current line of header file */
+ uint16_t len; /*length of the current len */
+{
+ size_t nlen = strlen(line) -2;
+ for (int i = 0; i < nlen; ++i) {
+ if (line[i] == ':') {
+ HeaderKV *headerkv = out_header->h_parsed;
+ memcpy(headerkv[out_header->parsed_size - 1].key, line, i + 1);
+ headerkv[out_header->parsed_size - 1].key[i] = '\0';
+
+ size_t value_size = nlen - i - 1;
+ memcpy(headerkv[out_header->parsed_size - 1].value, line + i + 1,
+ value_size);
+ return;
+ }
+ }
+} //allocHeaderKV()
+
+void allocHeaderCallback(line, len, data, linenum)
+ char *line;
+ size_t len;
+ void *data;
+ uint32_t linenum;
+{
+ HttpHeader *out_header = (HttpHeader *) data;
+ if (linenum == 1) {
+ memcpy(out_header->protocol, line, strlen(line) - 2);
+ return;
+ };
+
+ out_header->parsed_size++;
+
+ if (out_header->parsed_size == 1) {
+ out_header->h_parsed = (HeaderKV *)malloc(sizeof(HeaderKV) *
+ (out_header->parsed_size));
+ } else {
+ out_header->h_parsed = (HeaderKV *)realloc(out_header->h_parsed,
+ sizeof(HeaderKV) *
+ (out_header->parsed_size));
+ }
+
+ allocHeaderKV(out_header, line, len);
+} // allocHeaderCallback()
+
+void htmlFile2Header_alloc(out_header, header_path)
+ // SYNOPSIS:
+ // Gets info from a http header file to a @out_header stgruct
+
+ HttpHeader *out_header;
+ char *header_path;
+{
+ out_header->fp = fopen(header_path, "r");
+ out_header->parsed_size = 0;
+ readLines(out_header->fp, out_header, allocHeaderCallback);
+} // htmlFile2Header_alloc()
+
+void htmlFile2Header_dealloc(header)
+ HttpHeader *header;
+{
+ free(header->h_parsed);
+ fclose(header->fp);
+} // htmlFile2Header_dealloc()
+
+bool match(char *comp, char *str, regmatch_t *pmatch)
+ // SYNOPSIS:
+ // Sees if str matches the comp regex. if it does it returns true and
+ // stores the locat
+{
+ regex_t regex;
+ regmatch_t lpmatch[1];
+ int reti = regcomp(®ex, comp, 0);
+ if (reti) {
+ fprintf(stderr, "Could not compile regex at\n%s line %d\n", __FILE__,
+ __LINE__);
+ }
+ bool match = (regexec(®ex, str, sizeof(lpmatch) / sizeof(lpmatch[0]),
+ lpmatch, 0) == 0);
+ if (pmatch) {
+ memcpy(&pmatch->rm_so, &lpmatch[0].rm_so, sizeof(lpmatch[0].rm_so));
+ memcpy(&pmatch->rm_eo, &lpmatch[0].rm_eo, sizeof(lpmatch[0].rm_eo));
+ }
+ regfree(®ex);
+ return match;
+} // match()
+
+void getHtmlInfoCallback(line, len, data, linenum)
+ char *line;
+ size_t len;
+ void *data;
+ uint32_t linenum;
+{
+ Html *out_html = (Html *)data;
+ char startTagReg[] = "<[a-z0-9]*>";
+ char endTagReg[] = "</[a-z0-9]*>";
+ regmatch_t pmatch;
+ out_html->lines_count++;
+ uint32_t rlen = strlen(line);
+ out_html->lines_size += rlen;
+
+
+ int j = out_html->lines_count - 1;
+
+ if (out_html->lines_count == 1) {
+ out_html->h_lines = (char **)malloc(out_html->lines_size);
+ out_html->h_lines[j] = (char *)malloc(rlen);
+ } else {
+ out_html->h_lines = (char **)realloc(out_html->h_lines,
+ out_html->lines_size);
+ out_html->h_lines[j] = (char *)malloc(rlen);
+ }
+
+ memcpy(out_html->h_lines[j], line, rlen);
+
+ int i = out_html->tag_count - 1;
+
+ if (match(startTagReg, line, &pmatch)) {
+ uint16_t matchlen = pmatch.rm_eo - pmatch.rm_so;
+
+ out_html->tag_count++;
+ i = out_html->tag_count - 1;
+
+ if (out_html->tag_count == 1) {
+ out_html->h_tags = malloc(sizeof(Tag) * out_html->tag_count);
+ } else {
+ out_html->h_tags = realloc(out_html->h_tags, sizeof(Tag) *
+ out_html->tag_count);
+ }
+
+ out_html->h_tags[i].startline = j;
+
+ char name[50];
+
+ memset(name, 0, 10);
+ memset(out_html->h_tags[i].name, 0, 10);
+ memcpy(out_html->h_tags[i].name,
+ line + pmatch.rm_so + 1, matchlen - 2);
+
+ memcpy(&out_html->h_tags[i].start, &pmatch,
+ sizeof(regmatch_t));
+ }
+
+ if (match(endTagReg, line, &pmatch)) {
+ uint16_t matchlen = pmatch.rm_eo - pmatch.rm_so;
+ char name[50];
+ memset(name, 0, 10);
+ memcpy(name, line + pmatch.rm_so + 2, matchlen - 3);
+
+ for (int k = 0; k < out_html->tag_count; ++k) {
+ if (!strcmp(out_html->h_tags[k].name, name)) {
+ out_html->h_tags[k].endline = j;
+ memcpy(&out_html->h_tags[k].end, &pmatch,
+ sizeof(regmatch_t));
+ }
+ }
+ }
+
+} // getHtmlInfoCallback()
+
+
+void htmlFile2Str_alloc (out_html, html_path)
+ // SYNOPSIS:
+ // Gets info from a html file.
+ //
+ // It gets the html_path from @html_path, reads the file, and then places
+ // information about the file into the @out_html struct
+
+ Html *out_html; /* struct the gets allocated with information from the
+ * html file */
+ char *html_path; /* path of the html file */
+{
+ out_html->tag_count = 0;
+ out_html->lines_count = 0;
+ out_html->lines_size = 0;
+ out_html->h_tags = NULL;
+ out_html->fp = fopen(html_path, "r");
+ readLines(out_html->fp, (void *)out_html, getHtmlInfoCallback);
+ rewind(out_html->fp);
+} // htmlFile2Str_alloc()
+
+void htmlFile2Str_dealloc (out_html)
+ Html *out_html; /* struct that gets its contents deallocated*/
+{
+ if (out_html->h_tags) free(out_html->h_tags);
+
+ for (uint32_t i = 0; i < out_html->lines_count; ++i) {
+ if (out_html->h_lines[i])
+ free(out_html->h_lines[i]);
+ }
+
+ if (out_html->h_lines)
+ free(out_html->h_lines);
+
+ fclose(out_html->fp);
+} // htmlFile2Str_dealloc()
+
+
+void searchFileType(search_path, filetype, callback)
+ // SYNOPSIS:
+ // SearchsByFileType and then performs job based on the search
+
+ char *search_path; /* path to search for files */
+ char *filetype; /* type of file to search for ex. html, js, css*/
+ void (*callback) /* job to be done once the filetype is found */
+ (char *file_path, /* full path for the file found in the loop */
+ char *file_name); /* file name for the file found in the loop */
+
+{
+ regex_t regex;
+ struct dirent *files;
+
+ DIR *dir = opendir(search_path);
+
+ if (!dir) {
+ fprintf(stderr, "cannot open public directory at\n%s line %d\n",
+ __FILE__, __LINE__);
+ return;
+ }
+
+ char type[255] = ".";
+ strcat(type, filetype);
+ strcat(type, "$");
+
+ int reti = regcomp(®ex, type, 0);
+ if (reti) {
+ fprintf(stderr, "Could not compile regex at\n%s line %d\n", __FILE__,
+ __LINE__);
+ }
+
+ while ((files = readdir(dir)) != NULL) {
+ reti = regexec(®ex, files->d_name, 0, NULL, 0);
+ if (!reti) {
+ char file_path[255] = "./public/";
+ strcat(file_path, files->d_name);
+ callback(file_path, files->d_name);
+ }
+ }
+
+ regfree(®ex);
+ closedir(dir);
+} // searchFileType()
+
+
+void luaTag_alloc(LuaTag *luaTag, lua_State *L)
+{
+ memset(luaTag, 0, sizeof(LuaTag));
+ luaTag->in_tag = false;
+ luaTag->state = L;
+ luaTag->lines_count = 0;
+} // luaTag_alloc()
+
+void luaTag_dealloc(LuaTag *luaTag, lua_State *L)
+{
+ lua_close(L);
+} // luaTag_dealloc()
+
+int l_tagToStr(L)
+ lua_State *L;
+{
+ // because everything is pushed onto the stack
+ // -1 if second argumnet
+ // -2 is first argument
+ const bool isInner = lua_toboolean(L, -1);
+ const char *tagname = lua_tostring(L, -2);
+ lua_getglobal(L, "html");
+ Html *html = (Html *)lua_touserdata(L, -1);
+
+ uint8_t outlen = 0;
+ char *out = NULL;
+
+ bool startcontent = false;
+ for (uint32_t i = 0; i < html->lines_count; ++i) {
+ char *line = html->h_lines[i];
+
+ for (int j = 0; j < html->tag_count; ++j) {
+ char *name = html->h_tags[j].name;
+ if (!strcmp(tagname, name)) {
+
+ if (html->h_tags[j].startline == i) {
+ startcontent = true;
+ if (isInner) continue;
+ }
+ if (html->h_tags[j].endline == i) {
+ if (isInner) {
+ startcontent = false;
+ break;
+ };
+ }
+
+ if (startcontent) {
+ uint16_t len = strlen(line);
+ outlen += len;
+
+ if (!out) {
+ out = malloc(len);
+ } else {
+ out = realloc(out, outlen);
+ }
+
+ memcpy(out + outlen - len, line, len);
+ }
+
+ if (html->h_tags[j].endline == i) {
+ startcontent = false;
+ }
+ }
+ }
+ }
+ lua_pushstring(L, out);
+ free(out);
+ return 1;
+} // l_tagToStr()
+ //
+
+#endif // _PARSE_H_
--- /dev/null
+/*
+ * Copyright (C) 2024 Austin Larsen
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef PERR
+#define PERR
+#include <stdio.h>
+#define PERROR(s) fprintf(stderr, #s " (%d)\n%s %s:%d\n", errno, \
+ __FILE__, __FUNCTION__ , __LINE__);
+#endif // PERR
--- /dev/null
+<form action="https://localhost/" method="post">
+ <label for="fname">First name:</label><br>
+ <input type="text" id="fname" name="fname"><br>
+ <label for="lname">Last name:</label><br>
+ <input type="text" id="lname" name="lname">
+ <input type="submit" value="Go" />
+</form>
+
+<lua>
+print("this is from lua!")
+</lua>
--- /dev/null
+#ifndef _RENDER_H_
+#define _RENDER_H_
+
+#define _GNU_SOURCE
+
+#include "config.h"
+#include "net.h"
+#include "parse.h"
+
+typedef struct _Render
+{
+ char h_buffer[4096];
+ LuaTag *luaTag;
+ Html *html;
+}
+Render;
+
+void getRenderInfoCallback(line, len, data, linenum)
+ char *line;
+ size_t len;
+ void *data;
+ uint32_t linenum;
+{
+ Render *render = (Render *)data;
+ size_t rlen = strlen(line) + 1;
+
+ if (strstr(line, STARTTAG)) {
+ render->luaTag->in_tag = true;
+ return;
+ }
+
+ if (strstr(line, ENDTAG)) {
+ render->luaTag->in_tag = false;
+ return;
+ }
+
+ if (render->luaTag->in_tag) {
+ strncat(render->luaTag->h_buffer, line, rlen);
+ render->luaTag->lines_count++;
+
+ } else {
+ strncat(render->h_buffer, line, rlen + 1);
+ }
+} // getRenderInfoCallback()
+
+void renderInit(render, luaTag, html, header)
+ Render *render;
+ LuaTag *luaTag;
+ Html *html;
+ HttpHeader *header;
+{
+ render->luaTag = luaTag;
+ render->html = html;
+
+ char proto[500];
+ sprintf(proto, "%s\r\n", header->protocol);
+ int plen = strlen(proto);
+ strncat(render->h_buffer, proto, plen);
+ /* printf("%s\n", header->protocol); */
+
+
+ for (int i = 0; i < header->parsed_size; ++i) {
+ char kv[512];
+ memset(kv, 0, 512);
+ sprintf(kv, "%s:%s\r\n", header->h_parsed[i].key,
+ header->h_parsed[i].value);
+
+ int kvlen = strlen(kv);
+
+ strncat(render->h_buffer, kv, kvlen);
+ }
+
+ strncat(render->h_buffer, "\r\n", 3);
+}
+
+
+void renderFree(render)
+ Render render;
+{
+}
+
+
+
+#endif // _RENDER_H_
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 2.0.20">
+<title>Low Level Website</title>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
+<style>
+/*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
+/* Uncomment the following line when using as a custom stylesheet */
+/* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
+html{font-family:sans-serif;-webkit-text-size-adjust:100%}
+a{background:none}
+a:focus{outline:thin dotted}
+a:active,a:hover{outline:0}
+h1{font-size:2em;margin:.67em 0}
+b,strong{font-weight:bold}
+abbr{font-size:.9em}
+abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}
+dfn{font-style:italic}
+hr{height:0}
+mark{background:#ff0;color:#000}
+code,kbd,pre,samp{font-family:monospace;font-size:1em}
+pre{white-space:pre-wrap}
+q{quotes:"\201C" "\201D" "\2018" "\2019"}
+small{font-size:80%}
+sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
+sup{top:-.5em}
+sub{bottom:-.25em}
+img{border:0}
+svg:not(:root){overflow:hidden}
+figure{margin:0}
+audio,video{display:inline-block}
+audio:not([controls]){display:none;height:0}
+fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
+legend{border:0;padding:0}
+button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
+button,input{line-height:normal}
+button,select{text-transform:none}
+button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
+button[disabled],html input[disabled]{cursor:default}
+input[type=checkbox],input[type=radio]{padding:0}
+button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
+textarea{overflow:auto;vertical-align:top}
+table{border-collapse:collapse;border-spacing:0}
+*,::before,::after{box-sizing:border-box}
+html,body{font-size:100%}
+body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
+a:hover{cursor:pointer}
+img,object,embed{max-width:100%;height:auto}
+object,embed{height:100%}
+img{-ms-interpolation-mode:bicubic}
+.left{float:left!important}
+.right{float:right!important}
+.text-left{text-align:left!important}
+.text-right{text-align:right!important}
+.text-center{text-align:center!important}
+.text-justify{text-align:justify!important}
+.hide{display:none}
+img,object,svg{display:inline-block;vertical-align:middle}
+textarea{height:auto;min-height:50px}
+select{width:100%}
+.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
+div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}
+a{color:#2156a5;text-decoration:underline;line-height:inherit}
+a:hover,a:focus{color:#1d4b8f}
+a img{border:0}
+p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
+p aside{font-size:.875em;line-height:1.35;font-style:italic}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
+h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
+h1{font-size:2.125em}
+h2{font-size:1.6875em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
+h4,h5{font-size:1.125em}
+h6{font-size:1em}
+hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}
+em,i{font-style:italic;line-height:inherit}
+strong,b{font-weight:bold;line-height:inherit}
+small{font-size:60%;line-height:inherit}
+code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
+ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
+ul,ol{margin-left:1.5em}
+ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}
+ul.circle{list-style-type:circle}
+ul.disc{list-style-type:disc}
+ul.square{list-style-type:square}
+ul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit}
+ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
+dl dt{margin-bottom:.3125em;font-weight:bold}
+dl dd{margin-bottom:1.25em}
+blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
+blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
+@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
+h1{font-size:2.75em}
+h2{font-size:2.3125em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
+h4{font-size:1.4375em}}
+table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}
+table thead,table tfoot{background:#f7f8f7}
+table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
+table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
+table tr.even,table tr.alt{background:#f8f8f7}
+table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
+h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
+.center{margin-left:auto;margin-right:auto}
+.stretch{width:100%}
+.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
+.clearfix::after,.float-group::after{clear:both}
+:not(pre).nobreak{word-wrap:normal}
+:not(pre).nowrap{white-space:nowrap}
+:not(pre).pre-wrap{white-space:pre-wrap}
+:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
+pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
+pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
+pre>code{display:block}
+pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
+em em{font-style:normal}
+strong strong{font-weight:400}
+.keyseq{color:rgba(51,51,51,.8)}
+kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
+.keyseq kbd:first-child{margin-left:0}
+.keyseq kbd:last-child{margin-right:0}
+.menuseq,.menuref{color:#000}
+.menuseq b:not(.caret),.menuref{font-weight:inherit}
+.menuseq{word-spacing:-.02em}
+.menuseq b.caret{font-size:1.25em;line-height:.8}
+.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
+b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
+b.button::before{content:"[";padding:0 3px 0 2px}
+b.button::after{content:"]";padding:0 2px 0 3px}
+p a>code:hover{color:rgba(0,0,0,.9)}
+#header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
+#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
+#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
+#content{margin-top:1.25em}
+#content::before{content:none}
+#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
+#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
+#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
+#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}
+#header .details span:first-child{margin-left:-.125em}
+#header .details span.email a{color:rgba(0,0,0,.85)}
+#header .details br{display:none}
+#header .details br+span::before{content:"\00a0\2013\00a0"}
+#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
+#header .details br+span#revremark::before{content:"\00a0|\00a0"}
+#header #revnumber{text-transform:capitalize}
+#header #revnumber::after{content:"\00a0"}
+#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
+#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
+#toc>ul{margin-left:.125em}
+#toc ul.sectlevel0>li>a{font-style:italic}
+#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
+#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
+#toc li{line-height:1.3334;margin-top:.3334em}
+#toc a{text-decoration:none}
+#toc a:active{text-decoration:underline}
+#toctitle{color:#7a2518;font-size:1.2em}
+@media screen and (min-width:768px){#toctitle{font-size:1.375em}
+body.toc2{padding-left:15em;padding-right:0}
+#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
+#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
+#toc.toc2>ul{font-size:.9em;margin-bottom:0}
+#toc.toc2 ul ul{margin-left:0;padding-left:1em}
+#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
+body.toc2.toc-right{padding-left:0;padding-right:15em}
+body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
+@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
+#toc.toc2{width:20em}
+#toc.toc2 #toctitle{font-size:1.375em}
+#toc.toc2>ul{font-size:.95em}
+#toc.toc2 ul ul{padding-left:1.25em}
+body.toc2.toc-right{padding-left:0;padding-right:20em}}
+#content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}
+#content #toc>:first-child{margin-top:0}
+#content #toc>:last-child{margin-bottom:0}
+#footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}
+#footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}
+#content{margin-bottom:.625em}
+.sect1{padding-bottom:.625em}
+@media screen and (min-width:768px){#content{margin-bottom:1.25em}
+.sect1{padding-bottom:1.25em}}
+.sect1:last-child{padding-bottom:0}
+.sect1+.sect1{border-top:1px solid #e7e7e9}
+#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
+#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
+#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
+#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
+#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
+details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
+details{margin-left:1.25rem}
+details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}
+details>summary::-webkit-details-marker{display:none}
+details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}
+details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}
+details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}
+.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
+table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
+.paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
+.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
+.admonitionblock>table td.icon{text-align:center;width:80px}
+.admonitionblock>table td.icon img{max-width:none}
+.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
+.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}
+.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
+.exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}
+.sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}
+.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
+.exampleblock>.content>:first-child,.sidebarblock>.content>:first-child{margin-top:0}
+.exampleblock>.content>:last-child,.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
+.literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}
+@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
+@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
+.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
+.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
+.listingblock>.content{position:relative}
+.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
+.listingblock:hover code[data-lang]::before{display:block}
+.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
+.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
+.listingblock pre.highlightjs{padding:0}
+.listingblock pre.highlightjs>code{padding:1em;border-radius:4px}
+.listingblock pre.prettyprint{border-width:0}
+.prettyprint{background:#f7f7f8}
+pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
+pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
+pre.prettyprint li code[data-lang]::before{opacity:1}
+pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
+table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
+table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
+table.linenotable td.code{padding-left:.75em}
+table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
+pre.pygments span.linenos{display:inline-block;margin-right:.75em}
+.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
+.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
+.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
+.quoteblock blockquote{margin:0;padding:0;border:0}
+.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
+.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
+.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
+.verseblock{margin:0 1em 1.25em}
+.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
+.verseblock pre strong{font-weight:400}
+.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
+.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
+.quoteblock .attribution br,.verseblock .attribution br{display:none}
+.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
+.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
+.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
+.quoteblock.abstract{margin:0 1em 1.25em;display:block}
+.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
+.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
+.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
+.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
+.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}
+p.tableblock:last-child{margin-bottom:0}
+td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}
+td.tableblock>.content>:last-child{margin-bottom:-1.25em}
+table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
+table.grid-all>*>tr>*{border-width:1px}
+table.grid-cols>*>tr>*{border-width:0 1px}
+table.grid-rows>*>tr>*{border-width:1px 0}
+table.frame-all{border-width:1px}
+table.frame-ends{border-width:1px 0}
+table.frame-sides{border-width:0 1px}
+table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}
+table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}
+table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}
+table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}
+table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}
+th.halign-left,td.halign-left{text-align:left}
+th.halign-right,td.halign-right{text-align:right}
+th.halign-center,td.halign-center{text-align:center}
+th.valign-top,td.valign-top{vertical-align:top}
+th.valign-bottom,td.valign-bottom{vertical-align:bottom}
+th.valign-middle,td.valign-middle{vertical-align:middle}
+table thead th,table tfoot th{font-weight:bold}
+tbody tr th{background:#f7f8f7}
+tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
+p.tableblock>code:only-child{background:none;padding:0}
+p.tableblock{font-size:1em}
+ol{margin-left:1.75em}
+ul li ol{margin-left:1.5em}
+dl dd{margin-left:1.125em}
+dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
+li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
+ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
+ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
+ul.unstyled,ol.unstyled{margin-left:0}
+li>p:empty:only-child::before{content:"";display:inline-block}
+ul.checklist>li>p:first-child{margin-left:-1em}
+ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
+ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}
+ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
+ul.inline>li{margin-left:1.25em}
+.unstyled dl dt{font-weight:400;font-style:normal}
+ol.arabic{list-style-type:decimal}
+ol.decimal{list-style-type:decimal-leading-zero}
+ol.loweralpha{list-style-type:lower-alpha}
+ol.upperalpha{list-style-type:upper-alpha}
+ol.lowerroman{list-style-type:lower-roman}
+ol.upperroman{list-style-type:upper-roman}
+ol.lowergreek{list-style-type:lower-greek}
+.hdlist>table,.colist>table{border:0;background:none}
+.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
+td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
+td.hdlist1{font-weight:bold;padding-bottom:1.25em}
+td.hdlist2{word-wrap:anywhere}
+.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
+.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
+.colist td:not([class]):first-child img{max-width:none}
+.colist td:not([class]):last-child{padding:.25em 0}
+.thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}
+.imageblock.left{margin:.25em .625em 1.25em 0}
+.imageblock.right{margin:.25em 0 1.25em .625em}
+.imageblock>.title{margin-bottom:0}
+.imageblock.thumb,.imageblock.th{border-width:6px}
+.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
+.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
+.image.left{margin-right:.625em}
+.image.right{margin-left:.625em}
+a.image{text-decoration:none;display:inline-block}
+a.image object{pointer-events:none}
+sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
+sup.footnote a,sup.footnoteref a{text-decoration:none}
+sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
+#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
+#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
+#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
+#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
+#footnotes .footnote:last-of-type{margin-bottom:0}
+#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
+div.unbreakable{page-break-inside:avoid}
+.big{font-size:larger}
+.small{font-size:smaller}
+.underline{text-decoration:underline}
+.overline{text-decoration:overline}
+.line-through{text-decoration:line-through}
+.aqua{color:#00bfbf}
+.aqua-background{background:#00fafa}
+.black{color:#000}
+.black-background{background:#000}
+.blue{color:#0000bf}
+.blue-background{background:#0000fa}
+.fuchsia{color:#bf00bf}
+.fuchsia-background{background:#fa00fa}
+.gray{color:#606060}
+.gray-background{background:#7d7d7d}
+.green{color:#006000}
+.green-background{background:#007d00}
+.lime{color:#00bf00}
+.lime-background{background:#00fa00}
+.maroon{color:#600000}
+.maroon-background{background:#7d0000}
+.navy{color:#000060}
+.navy-background{background:#00007d}
+.olive{color:#606000}
+.olive-background{background:#7d7d00}
+.purple{color:#600060}
+.purple-background{background:#7d007d}
+.red{color:#bf0000}
+.red-background{background:#fa0000}
+.silver{color:#909090}
+.silver-background{background:#bcbcbc}
+.teal{color:#006060}
+.teal-background{background:#007d7d}
+.white{color:#bfbfbf}
+.white-background{background:#fafafa}
+.yellow{color:#bfbf00}
+.yellow-background{background:#fafa00}
+span.icon>.fa{cursor:default}
+a span.icon>.fa{cursor:inherit}
+.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
+.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
+.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
+.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
+.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
+.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
+.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
+.conum[data-value] *{color:#fff!important}
+.conum[data-value]+b{display:none}
+.conum[data-value]::after{content:attr(data-value)}
+pre .conum[data-value]{position:relative;top:-.125em}
+b.conum *{color:inherit!important}
+.conum:not([data-value]):empty{display:none}
+dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
+h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}
+p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
+p,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:1.0625rem}
+p{margin-bottom:1.25rem}
+.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
+.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}
+.print-only{display:none!important}
+@page{margin:1.25cm .75cm}
+@media print{*{box-shadow:none!important;text-shadow:none!important}
+html{font-size:80%}
+a{color:inherit!important;text-decoration:underline!important}
+a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
+a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
+abbr[title]{border-bottom:1px dotted}
+abbr[title]::after{content:" (" attr(title) ")"}
+pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
+thead{display:table-header-group}
+svg{max-width:100%}
+p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
+h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
+#header,#content,#footnotes,#footer{max-width:none}
+#toc,.sidebarblock,.exampleblock>.content{background:none!important}
+#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
+body.book #header{text-align:center}
+body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
+body.book #header .details{border:0!important;display:block;padding:0!important}
+body.book #header .details span:first-child{margin-left:0!important}
+body.book #header .details br{display:block}
+body.book #header .details br+span::before{content:none!important}
+body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
+body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
+.listingblock code[data-lang]::before{display:block}
+#footer{padding:0 .9375em}
+.hide-on-print{display:none!important}
+.print-only{display:block!important}
+.hide-for-print{display:none!important}
+.show-for-print{display:inherit!important}}
+@media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}
+.sect1{padding:0!important}
+.sect1+.sect1{border:0}
+#footer{background:none}
+#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
+@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
+</style>
+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+<head>
+<!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=DotGothic16"> -->
+<!-- <link rel="icon" type="image/x-icon" href="https://raw.githubusercontent.com/A-Larsen/math-notes/refs/heads/main/favicon.png"> -->
+<!-- <link rel="icon" type="image/png" href="N2DE_favicon.png"/> -->
+<!-- <link rel="preconnect" href="https://fonts.googleapis.com"> -->
+<!-- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> -->
+<!-- <link href="https://fonts.googleapis.com/css2?family=Abril+Fatface&display=swap" rel="stylesheet"> -->
+<style>
+
+/*--------------------------------------------------------------*/
+/*use '!important' to override default css used by asciidoctor*/
+/*--------------------------------------------------------------*/
+
+:root {
+ --gruvbox-black: #282828;
+ --gruvbox-black2: #1d2021;
+ --gruvbox-black3: #463f39;
+ --gruvbox-red: #fc7869;
+ --gruvbox-yellow: #fabd2f;
+ --gruvbox-white: #ebdbb2;
+ --gruvbox-white2: #a7a187;
+ --gruvbox-blue: #83a598;
+ --gruvbox-green: #b8bb26;
+ --gruvbox-bg1: #7c6f64;
+ --gruvbox-bg2: #665c54;
+
+}
+
+.title {
+ color: var(--gruvbox-red) !important;
+}
+
+blockquote {
+ color: var(--gruvbox-white) !important;
+}
+
+table {
+ margin: 0 auto !important;
+}
+
+.hdlist1 {
+ font-size: 1.3em;
+}
+
+cite {
+ color: var(--gruvbox-green) !important;
+}
+
+.tableblock {
+ background-color: inherit;
+ color: var(--gruvbox-white);
+ max-width: 95%;
+}
+
+.tableblock th {
+ background-color: var(--gruvbox-black3);
+ color: var(--gruvbox-white);
+ max-width: 97%;
+}
+
+code:not([data-lang]) {
+ background-color: var(--gruvbox-bg2) !important;
+ color: var(--gruvbox-white);
+ text-shadow: none;
+}
+
+.checklist {
+ text-align: left;
+ font-size: .8em;
+}
+
+.checklist li ul { margin-left: 3%;
+}
+
+#content, h1, pre {
+ border-radius: 8px !important;
+}
+
+#header, #content, #footnotes, #footer {
+ padding-left: 0 !important;
+ padding-right: 0 !important;
+}
+
+.api-type a:hover {
+ text-decoration: underline;
+}
+
+.api-type, .api-type a {
+ color: var(--gruvbox-green);
+ text-decoration: none;
+}
+
+pre {
+ border-style: solid !important;
+ border-color: white !important;
+ border-width: 2px !important;
+}
+
+h1 {
+ /* font-family: "DotGothic16", sans-serif !important;*/
+
+
+ background-color: var(--gruvbox-white2) !important;
+ color: var(--gruvbox-black) !important;
+}
+
+.admonitionblock > table td.content {
+ color: var(--gruvbox-white) !important;
+}
+
+/*
+html {
+ margin: 0;
+ height: 100%;
+ width: 100%;
+}
+
+
+*/
+/*html {*/
+
+body {
+ /*background: black url("background-image-space.jpeg") no-repeat fixed center;*/
+ /*background-color: black;*/
+ background-color: var(--gruvbox-black);
+ background-attachment: fixed;
+ background-size: cover;
+ overflow-y: scroll;
+ /*
+ margin: 0;
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+ */
+}
+
+
+/*
+body {
+ overflow-y: scroll;
+ background: rgba(0,0,0,0);
+ height: 100%;
+ margin: 2%;
+}
+*/
+
+#toc {
+ background-color: var(--gruvbox-black2) !important;
+ /*opacity: .9;*/
+}
+
+#toctitle {
+ color: var(--gruvbox-yellow);
+}
+
+a {
+ color: var(--gruvbox-bg1);
+}
+
+#content {
+ color: #ebdbb2;
+ background: var(--gruvbox-black);
+ /*opacity: .9;*/
+}
+
+#header > h1:nth-last-child(2) {
+ border-bottom: none !important;
+ background-color: rgba(0, 0, 0, .1);
+ padding-left: 2%;
+}
+
+.sect1 + .sect1 {
+ border-top: none !important;
+}
+
+.sect1 h2 {
+ background-size: cover;
+ background-attachment: fixed;
+ /*
+ border-bottom: 1px solid var(--gruvbox-white);
+ border-top: 1px solid var(--gruvbox-white);
+ */
+ padding: 10px;
+ text-align: left;
+ color: var(--gruvbox-red) !important;
+ /*
+ text-shadow: 1px 1px 1px var(--gruvbox-black);
+ text-shadow: 3px 3px 3px var(--gruvbox-black);
+ text-shadow: 5px 5px 5px var(--gruvbox-blue);
+ */
+}
+
+h3, h4, h5 {
+ /*
+ text-shadow: 1px 1px 1px var(--gruvbox-white);
+ */
+}
+
+h3 {
+ color: var(--gruvbox-red) !important;
+}
+
+h4 {
+ color: var(--gruvbox-yellow) !important;
+}
+
+h5 {
+ color: #83a598 !important;
+}
+
+h2 ~ *:not(h1) {
+ margin-left: .5em;
+}
+
+.pygments {
+ max-width: 97% !important;
+ white-space: pre;
+ overflow-x: scroll !important;
+}
+
+::before {
+ /*makes sure that the programming language that show up on hover is within
+ pre tag*/
+ padding-right: 3%;
+}
+
+@media screen and (max-width: 800px) {
+ .checklist li ul {
+ margin-left: 6% !important;
+ }
+ #toc {
+ padding-left: 10px;
+ }
+
+ footer {
+ margin-bottom: 10px !important;
+ }
+ html {
+ margin-bottom: 10px !important;
+ }
+}
+@media screen and (max-width: 535px) {
+ h3 ~ *:not(h2):not(h3) {
+ margin-left: 0 !important;
+ }
+
+ h4 ~ *:not(h2):not(h3):not(.h3):not(h4) {
+ margin-left: 0 !important;
+ }
+ h5 ~ *:not(h2):not(h3):not(.h3):not(h4):not(.h4):not(h5) {
+ margin-left: 0 !important;
+ }
+
+ footer {
+ margin-bottom: 10px !important;
+ }
+ html {
+ margin-bottom: 10px !important;
+ }
+}
+h3 ~ *:not(h2):not(h3) {
+ margin-left: 1.5em;
+}
+
+h4 ~ *:not(h2):not(h3):not(.h3):not(h4) {
+ margin-left: 2em;
+}
+h5 ~ *:not(h2):not(h3):not(.h3):not(h4):not(.h4):not(h5) {
+ margin-left: 2.5em;
+}
+
+
+.sect1 h2 {
+
+ /*
+ background: linear-gradient(
+ to bottom,
+ rgba(251, 189, 47, 0.2), /* yellow */
+ rgba(0, 0, 0, 0.4) /* black */
+ );
+ */
+ /*opacity: .9;*/
+ }
+
+#preamble p{
+ padding-left: 10px;
+ color: var(--gruvbox-white) !important;
+}
+
+#footer {
+ max-width: 62.5em !important;
+ padding-left: 10px !important;
+ text-align: center;
+}
+
+.logo img {
+ display: block !important;
+ margin-left: auto !important;
+ margin-right: auto !important;
+}
+
+#header > h1:first-child {
+ margin-top: .3em !important;
+ padding-top: .2em !important;
+ text-align: center;
+}
+
+footer {
+ max-width: 62.5em;
+ margin-left: auto;
+ margin-right: auto;
+ display: block;
+
+}
+
+details[open] > summary::before {
+ /* display: none;*/
+ border-top: none;
+ content: "▼";
+ margin-top: -12px;
+}
+
+.example.stemblock {
+ border: solid;
+ font-size: 2vw;
+ max-width: 40%;
+ margin: auto;
+}
+
+.center {
+ max-width: 500px;
+ display: flex;
+ justify-content: center;
+}
+
+.highlight {
+ color: var(--gruvbox-yellow)
+}
+
+.border {
+ padding: 4px;
+ border: 2px solid rgba(255, 0, 0, .3);
+}
+
+.dull {
+ opacity: 40%;
+}
+
+.inline {
+ margin-right: 5%;
+ display: inline-block;
+}
+
+
+</style>
+
+</head>
+
+<script src="docinfo.js"></script>
+
+
+</head>
+<body class="article">
+<div id="header">
+<h1>Low Level Website</h1>
+</div>
+<div id="content">
+<div id="preamble">
+<div class="sectionbody">
+<div class="paragraph">
+<p>A website made using low level libraries that incorporates ssl through openssl.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_running">Running</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>Run index to start the server. It does need to be ran as root so it can connect
+to a web socket. The server will be hosted on <a href="https://localhost" class="bare">https://localhost</a>. You also need
+to allow your browser to access the page because it might be considered unsafe
+if you don’t have the correct certificate files for openssl. Any html
+inside of the public directory will be rendered.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre>sudo ./index</pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_building">Building</h2>
+<div class="sectionbody">
+<div class="listingblock">
+<div class="content">
+<pre>make</pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+<script type="text/x-mathjax-config">
+MathJax.Hub.Config({
+ messageStyle: "none",
+ tex2jax: {
+ inlineMath: [["\\(", "\\)"]],
+ displayMath: [["\\[", "\\]"]],
+ ignoreClass: "nostem|nolatexmath"
+ },
+ asciimath2jax: {
+ delimiters: [["\\$", "\\$"]],
+ ignoreClass: "nostem|noasciimath"
+ },
+ TeX: { equationNumbers: { autoNumber: "none" } }
+})
+MathJax.Hub.Register.StartupHook("AsciiMath Jax Ready", function () {
+ MathJax.InputJax.AsciiMath.postfilterHooks.Add(function (data, node) {
+ if ((node = data.script.parentNode) && (node = node.parentNode) && node.classList.contains("stemblock")) {
+ data.math.root.display = "block"
+ }
+ return data
+ })
+})
+</script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.9/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDazCCAlOgAwIBAgIUDRvbhgRp/5zTuj0z6nXkGGCP8RkwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTA2MDYwMzU2NDBaFw0yMjA2
+MDYwMzU2NDBaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDDL0SeaSpf9NFMaocM++NEHGWSsIwX0ZdGknWXvUfc
+1Q4lCgnbmh1FWTstC5roCs+iP+eOSTGDqNKxYhc5yLgVvxyvb5nEc1UrpcSvrmqu
+MZ7KxrLksFi9044xmrBUCqhGAe86pibqzc6tQn0HfNBJNBachCVjjgpaEl9oZ6qT
+1VOLqRrtVKwrDzbF3l6VgOZ99LDV2Enwcklt8l5vzlG7e4CviGDsDsnxAtmIH/vm
+LutuvE6iUKK9KYaPfheMEm4c1JztJ5aPIFbjmP/6voLljoIGUWx5FY9sSAyh+vuo
++NgQrqbO6GWob7fMUFhMDCQdmi96Dhhf6rESeDWgxcf5AgMBAAGjUzBRMB0GA1Ud
+DgQWBBSiCTPm6DH4q7ZZp7uhi0xnYjHhTTAfBgNVHSMEGDAWgBSiCTPm6DH4q7ZZ
+p7uhi0xnYjHhTTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAn
+7Vt981M5HkB4QNAM4s75Wt3+MrrSqzSZHCSRU0mPESb9uncnvjLbdi2Sndo1ZkgL
+BaEjTsxoxhjZtx6Kc3ogZwFoM0iF1d2EF83wmvfDFWOLs/98/WrzbWoJF/BgqNIi
+MTncDqryKhBIJ0ETOThKEzfswldxTG8tPqaW6fglLzJjqDLxkKAPIpNlq8djt57Z
+iKQtOY0RQ44xbkNe0TUaeGXSshvFGdsGe2BIi5t4em+TBWnRNUiZMSVzhv5sWqt1
+LoRXmDG1INTs2ev0oj72N9eHRNH20nMagp529jwMkbxbpvSdjD40PJmsfdw1aGLb
+EzySebJEPgNHhRbiEVnP
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDL0SeaSpf9NFM
+aocM++NEHGWSsIwX0ZdGknWXvUfc1Q4lCgnbmh1FWTstC5roCs+iP+eOSTGDqNKx
+Yhc5yLgVvxyvb5nEc1UrpcSvrmquMZ7KxrLksFi9044xmrBUCqhGAe86pibqzc6t
+Qn0HfNBJNBachCVjjgpaEl9oZ6qT1VOLqRrtVKwrDzbF3l6VgOZ99LDV2Enwcklt
+8l5vzlG7e4CviGDsDsnxAtmIH/vmLutuvE6iUKK9KYaPfheMEm4c1JztJ5aPIFbj
+mP/6voLljoIGUWx5FY9sSAyh+vuo+NgQrqbO6GWob7fMUFhMDCQdmi96Dhhf6rES
+eDWgxcf5AgMBAAECggEASY50s6Y6W/MtNTkoMBJ1MWPqO3/hK9DGy8fCHS8t9+Eq
+9XZ1BJdt1IauMGmhNTVtzl167DpVOKLU1Bh9XD9ycG+XZd4O+uPkAxDzsKlwdrko
+eI6tOFXk+5TQj40WSnXBuLBd8aJQJEjvTIg0CjBVZmEE7HM4i+4ppIwr/HKk7BTd
+vwMapOBs42qvAl0EfaMIGP/AFbBKBcUQYmLC9Ui0OHbb8h4pqM5aMw6qNTt1HRm2
+2QT4OkSRT+hlueGhFHhKhg31LLmhojl/VX9xJ/RzT9aggnVEN7WpD5lSe2gBTs/q
+/jq/assTUdGz+NKNt4Znv5A0T+/5v06VnIdqyviQoQKBgQD0lbthtRlHgYhG/iFh
+4WVUg2DYxXVs7RKi76sv3wjy++6Sz4kpkErqbl6esCfg+esXual8Ef12pqIa8YGa
+goc91bTnXx6pOB/4tPF5gMFUNYOuI0/+hzWz7Wbp8CILE3D5mEISlc5uloXnhbQC
+yar3RPcT6pte9Qc8X5rCwB7OtQKBgQDMS07z6F4JQ28niMJJBrPhIJP1B7zbapRD
+OJIL13HKSRs9QyuPmQtMuWxOieGRTv7Q4WBXZDkZAtaNXQYY7dVp94412SyfBZTS
+sphyj5LNKzPO4SRlCpYcfkDoxDBU88zMuUA4NJkKnAeQW8Vf6kd6G93L+YsglF3c
+Bz94HkpatQKBgQCtocJlqcfpcHaLV4vhTb6+0YmmOf+TtXV+gEB5+o8C2IDUbkrE
+W/AjHvlDFHErEKCpth8wuiDC46a/E+XbB4D1D8qeWnOM1BA2YlXu2M3mdxslO2Jl
+oh0ov4dI2jWAwWt5dXKqePkUnv0ukEdrlzks0yPIWsu0DKT3YjOev/7e5QKBgEaa
+LCH9ByqaZHq8N7C3IUlHUfrXfrwxnCWTEl4HSesH0uMcKJzK3m3YkwadfhgSvduA
+WCQ7ncP4CB/4qxfIcf3aMQqJEHOwoRsj362P0sMXECOKCWLmArS8KUCINM/XJcsG
+ppwGCXHyNGb+YDrio2se4EsS5bMPs1RMKPIhPb8VAoGANPTvhDSXHEPFI3ZfOkJV
+NvoeI4qyuc5RLtPvrL5DThHLBqnUMrveyaO++e638+AenZ4c2QPNfOv2UogMIAON
+YdvAtWnEqEpeGOC+BFYCsmpm7iUh1exutXDywaZH0rghAYlCLjNpzjVXfmmDNIH/
+sFpKCBmo9JznTqgqkPjJHFk=
+-----END PRIVATE KEY-----
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDL0SeaSpf9NFM
+aocM++NEHGWSsIwX0ZdGknWXvUfc1Q4lCgnbmh1FWTstC5roCs+iP+eOSTGDqNKx
+Yhc5yLgVvxyvb5nEc1UrpcSvrmquMZ7KxrLksFi9044xmrBUCqhGAe86pibqzc6t
+Qn0HfNBJNBachCVjjgpaEl9oZ6qT1VOLqRrtVKwrDzbF3l6VgOZ99LDV2Enwcklt
+8l5vzlG7e4CviGDsDsnxAtmIH/vmLutuvE6iUKK9KYaPfheMEm4c1JztJ5aPIFbj
+mP/6voLljoIGUWx5FY9sSAyh+vuo+NgQrqbO6GWob7fMUFhMDCQdmi96Dhhf6rES
+eDWgxcf5AgMBAAECggEASY50s6Y6W/MtNTkoMBJ1MWPqO3/hK9DGy8fCHS8t9+Eq
+9XZ1BJdt1IauMGmhNTVtzl167DpVOKLU1Bh9XD9ycG+XZd4O+uPkAxDzsKlwdrko
+eI6tOFXk+5TQj40WSnXBuLBd8aJQJEjvTIg0CjBVZmEE7HM4i+4ppIwr/HKk7BTd
+vwMapOBs42qvAl0EfaMIGP/AFbBKBcUQYmLC9Ui0OHbb8h4pqM5aMw6qNTt1HRm2
+2QT4OkSRT+hlueGhFHhKhg31LLmhojl/VX9xJ/RzT9aggnVEN7WpD5lSe2gBTs/q
+/jq/assTUdGz+NKNt4Znv5A0T+/5v06VnIdqyviQoQKBgQD0lbthtRlHgYhG/iFh
+4WVUg2DYxXVs7RKi76sv3wjy++6Sz4kpkErqbl6esCfg+esXual8Ef12pqIa8YGa
+goc91bTnXx6pOB/4tPF5gMFUNYOuI0/+hzWz7Wbp8CILE3D5mEISlc5uloXnhbQC
+yar3RPcT6pte9Qc8X5rCwB7OtQKBgQDMS07z6F4JQ28niMJJBrPhIJP1B7zbapRD
+OJIL13HKSRs9QyuPmQtMuWxOieGRTv7Q4WBXZDkZAtaNXQYY7dVp94412SyfBZTS
+sphyj5LNKzPO4SRlCpYcfkDoxDBU88zMuUA4NJkKnAeQW8Vf6kd6G93L+YsglF3c
+Bz94HkpatQKBgQCtocJlqcfpcHaLV4vhTb6+0YmmOf+TtXV+gEB5+o8C2IDUbkrE
+W/AjHvlDFHErEKCpth8wuiDC46a/E+XbB4D1D8qeWnOM1BA2YlXu2M3mdxslO2Jl
+oh0ov4dI2jWAwWt5dXKqePkUnv0ukEdrlzks0yPIWsu0DKT3YjOev/7e5QKBgEaa
+LCH9ByqaZHq8N7C3IUlHUfrXfrwxnCWTEl4HSesH0uMcKJzK3m3YkwadfhgSvduA
+WCQ7ncP4CB/4qxfIcf3aMQqJEHOwoRsj362P0sMXECOKCWLmArS8KUCINM/XJcsG
+ppwGCXHyNGb+YDrio2se4EsS5bMPs1RMKPIhPb8VAoGANPTvhDSXHEPFI3ZfOkJV
+NvoeI4qyuc5RLtPvrL5DThHLBqnUMrveyaO++e638+AenZ4c2QPNfOv2UogMIAON
+YdvAtWnEqEpeGOC+BFYCsmpm7iUh1exutXDywaZH0rghAYlCLjNpzjVXfmmDNIH/
+sFpKCBmo9JznTqgqkPjJHFk=
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDazCCAlOgAwIBAgIUDRvbhgRp/5zTuj0z6nXkGGCP8RkwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTA2MDYwMzU2NDBaFw0yMjA2
+MDYwMzU2NDBaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDDL0SeaSpf9NFMaocM++NEHGWSsIwX0ZdGknWXvUfc
+1Q4lCgnbmh1FWTstC5roCs+iP+eOSTGDqNKxYhc5yLgVvxyvb5nEc1UrpcSvrmqu
+MZ7KxrLksFi9044xmrBUCqhGAe86pibqzc6tQn0HfNBJNBachCVjjgpaEl9oZ6qT
+1VOLqRrtVKwrDzbF3l6VgOZ99LDV2Enwcklt8l5vzlG7e4CviGDsDsnxAtmIH/vm
+LutuvE6iUKK9KYaPfheMEm4c1JztJ5aPIFbjmP/6voLljoIGUWx5FY9sSAyh+vuo
++NgQrqbO6GWob7fMUFhMDCQdmi96Dhhf6rESeDWgxcf5AgMBAAGjUzBRMB0GA1Ud
+DgQWBBSiCTPm6DH4q7ZZp7uhi0xnYjHhTTAfBgNVHSMEGDAWgBSiCTPm6DH4q7ZZ
+p7uhi0xnYjHhTTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAn
+7Vt981M5HkB4QNAM4s75Wt3+MrrSqzSZHCSRU0mPESb9uncnvjLbdi2Sndo1ZkgL
+BaEjTsxoxhjZtx6Kc3ogZwFoM0iF1d2EF83wmvfDFWOLs/98/WrzbWoJF/BgqNIi
+MTncDqryKhBIJ0ETOThKEzfswldxTG8tPqaW6fglLzJjqDLxkKAPIpNlq8djt57Z
+iKQtOY0RQ44xbkNe0TUaeGXSshvFGdsGe2BIi5t4em+TBWnRNUiZMSVzhv5sWqt1
+LoRXmDG1INTs2ev0oj72N9eHRNH20nMagp529jwMkbxbpvSdjD40PJmsfdw1aGLb
+EzySebJEPgNHhRbiEVnP
+-----END CERTIFICATE-----
--- /dev/null
+== Embeded C in html
+for the `readlines()` callback in `indexCallback()` create a token that only
+works with the server, like ejs `<%= %>`. Probably use lua in some way.
+
+== Lua function for inline css
+
+
+== Links
+- https://ejs.co/
+- https://stackshare.io/stackups/ejs-vs-pug