]> nyquistdev.net Git - low-level-website.git/commitdiff
first commit main
authorA-Larsen <austin.larsen@mailfence.com>
Thu, 15 Oct 2026 22:27:23 +0000 (18:27 -0400)
committerA-Larsen <austin.larsen@mailfence.com>
Thu, 15 Oct 2026 22:27:23 +0000 (18:27 -0400)
22 files changed:
LICENSE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README.adoc [new file with mode: 0644]
config.h [new file with mode: 0644]
docinfo.conf [new file with mode: 0644]
file.h [new file with mode: 0644]
http_headers/basic [new file with mode: 0644]
index [new file with mode: 0755]
index.c [new file with mode: 0644]
net.h [new file with mode: 0644]
notes.adoc [new file with mode: 0644]
other.adoc [new file with mode: 0644]
parse.h [new file with mode: 0644]
perr.h [new file with mode: 0644]
public/index.html [new file with mode: 0644]
public/index.js [new file with mode: 0644]
render.h [new file with mode: 0644]
rendered.html [new file with mode: 0644]
server.crt [new file with mode: 0644]
server.key [new file with mode: 0644]
server.pem [new file with mode: 0644]
todo.adoc [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,339 @@
+                    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.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..65143d5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,10 @@
+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)
diff --git a/README.adoc b/README.adoc
new file mode 100644 (file)
index 0000000..d34b3d7
--- /dev/null
@@ -0,0 +1,21 @@
+= 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
+----
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..5db1672
--- /dev/null
+++ b/config.h
@@ -0,0 +1,18 @@
+/* 
+ * 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"
diff --git a/docinfo.conf b/docinfo.conf
new file mode 100644 (file)
index 0000000..57fa5b9
--- /dev/null
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+HOSTNAME=nyquistdev.net
+DOCINFODIR=/usr/local/share/readme-to-html
diff --git a/file.h b/file.h
new file mode 100644 (file)
index 0000000..b1ceae3
--- /dev/null
+++ b/file.h
@@ -0,0 +1,53 @@
+/* 
+ * 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_
diff --git a/http_headers/basic b/http_headers/basic
new file mode 100644 (file)
index 0000000..a6155b7
--- /dev/null
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OK\r
+Connection: close\r
+Content-Type: text/html\r
diff --git a/index b/index
new file mode 100755 (executable)
index 0000000..b3713b3
Binary files /dev/null and b/index differ
diff --git a/index.c b/index.c
new file mode 100644 (file)
index 0000000..8b09ec6
--- /dev/null
+++ b/index.c
@@ -0,0 +1,106 @@
+/* 
+ * 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()
diff --git a/net.h b/net.h
new file mode 100644 (file)
index 0000000..2e63edf
--- /dev/null
+++ b/net.h
@@ -0,0 +1,320 @@
+/* 
+ * 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
diff --git a/notes.adoc b/notes.adoc
new file mode 100644 (file)
index 0000000..eef9237
--- /dev/null
@@ -0,0 +1,114 @@
+== 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
diff --git a/other.adoc b/other.adoc
new file mode 100644 (file)
index 0000000..3a6351e
--- /dev/null
@@ -0,0 +1 @@
+-- https://reqbin.com/Article/HttpGet
diff --git a/parse.h b/parse.h
new file mode 100644 (file)
index 0000000..fc2b575
--- /dev/null
+++ b/parse.h
@@ -0,0 +1,425 @@
+/* 
+ * 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(&regex, comp, 0);
+    if (reti) {
+        fprintf(stderr, "Could not compile regex at\n%s line %d\n", __FILE__, 
+                __LINE__);
+    }
+    bool match = (regexec(&regex, 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(&regex);
+    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(&regex, 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(&regex, 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(&regex);
+    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_
diff --git a/perr.h b/perr.h
new file mode 100644 (file)
index 0000000..4bac5ac
--- /dev/null
+++ b/perr.h
@@ -0,0 +1,23 @@
+/* 
+ * 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
diff --git a/public/index.html b/public/index.html
new file mode 100644 (file)
index 0000000..719a393
--- /dev/null
@@ -0,0 +1,11 @@
+<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>
diff --git a/public/index.js b/public/index.js
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/render.h b/render.h
new file mode 100644 (file)
index 0000000..a5edb2f
--- /dev/null
+++ b/render.h
@@ -0,0 +1,84 @@
+#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_
diff --git a/rendered.html b/rendered.html
new file mode 100644 (file)
index 0000000..3b5c681
--- /dev/null
@@ -0,0 +1,863 @@
+<!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&#8217;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
diff --git a/server.crt b/server.crt
new file mode 100644 (file)
index 0000000..fc4597b
--- /dev/null
@@ -0,0 +1,21 @@
+-----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-----
diff --git a/server.key b/server.key
new file mode 100644 (file)
index 0000000..0a125d9
--- /dev/null
@@ -0,0 +1,28 @@
+-----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-----
diff --git a/server.pem b/server.pem
new file mode 100644 (file)
index 0000000..9dd0640
--- /dev/null
@@ -0,0 +1,49 @@
+-----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-----
diff --git a/todo.adoc b/todo.adoc
new file mode 100644 (file)
index 0000000..9e606f5
--- /dev/null
+++ b/todo.adoc
@@ -0,0 +1,10 @@
+== 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