changeset 7:114cad94008f

[Seobeo] Updated to support thread and edge server calls.
author June Park <parkjune1995@gmail.com>
date Mon, 29 Sep 2025 17:00:38 -0700
parents 1e61008b9980
children 98f96b8032e5
files dowa/test_folder/bar/foo.txt mrjunejune/BUILD mrjunejune/main.c mrjunejune/pages/base.css mrjunejune/pages/fonts/Roboto-Regular.ttf mrjunejune/pages/fonts/Roboto-Thin.ttf mrjunejune/pages/fonts/atkinson-bold.woff mrjunejune/pages/fonts/atkinson-regular.woff mrjunejune/pages/index.html mrjunejune/pages/resume.css seobeo/BUILD seobeo/example.c seobeo/main.c seobeo/os/s_linux_edge.c seobeo/os/s_macos_edge.c seobeo/pages/hello/bar.txt seobeo/pages/hello/index.html seobeo/pages/hello/index.js seobeo/pages/index.js seobeo/s_web.c seobeo/seobeo.h
diffstat 21 files changed, 1149 insertions(+), 170 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dowa/test_folder/bar/foo.txt	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,1 @@
+hellow
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/BUILD	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,14 @@
+load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+
+filegroup(
+  name = "pages_files",
+  srcs = glob(["pages/**"]),
+)
+
+cc_binary(
+  name = "mrjunejune",
+  srcs = ["main.c"],
+  deps = ["//seobeo:seobeo"],
+  data = glob(["pages/**"]) + ["//seobeo:seobeo_headers"],
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/main.c	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,18 @@
+/**
+ *
+ * MrJuneJune
+ *
+ *   - Server side generated my blog created using entirely in C.
+ *   - Resume
+ *   - What have I done?
+ *   - Blogs....
+ *
+ */
+
+#include "seobeo/seobeo.h"
+
+
+int main(void)
+{
+  Seobeo_Web_StartBasicHTTPServer("mrjunejune/pages", "6969", SEOBEO_MODE_FORK, 2);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/pages/base.css	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,210 @@
+/* Base Colors */
+:root {
+  --white: #ffffff;
+  --black: hsl(224, 12%, 4%);
+  --darkgray: #333333;
+  --gray: #5d5d5d;
+  --lightgray: #999999;
+  --green: #c2e15f;
+  --orange: #fda333;
+  --purple: #d3a4f9;
+  --red: #fb4485;
+  --blue: #6ce0f1;
+  --darktext: #414141;
+  /* from astro */
+  --accent: #2337ff;
+  --accent-dark: #000d8a;
+  --gray: 96, 115, 159;
+  --gray-light: 229, 233, 240;
+  --gray-dark: 34, 41, 57;
+  --gray-gradient: rgba(var(--gray-light), 50%), #fff;
+  --box-shadow: 0 2px 6px rgba(var(--gray), 25%),
+    0 8px 24px rgba(var(--gray), 33%), 0 16px 32px rgba(var(--gray), 33%);
+  --awesome: #dc3522;
+  --main-width: 720px;
+}
+.dark {
+  --white: hsl(224, 10%, 10%);
+  --black: hsl(0, 0%, 90%);
+  --darkgray: #cccccc; /* Inverted */
+  --lightgray: #666666; /* Inverted */
+  --green: #3d1ea0; /* Complementary */
+  --orange: #025ccc; /* Complementary */
+  --purple: #2b5b06; /* Complementary */
+  --red: #04bb7a; /* Complementary */
+  --blue: #932f0e; /* Complementary */
+  --darktext: #bebebe; /* Inverted */
+  --text: var(--lightgray); /* Opposite of --darkgray */
+  --graytext: var(--lightgray); /* Opposite of --gray */
+  --lighttext: var(--darkgray); /* Opposite of --lightgray */
+  --awesome: #23cade; /* Complementary */
+
+  /* Opposite of Astro Colors */
+  --accent: #ffcc00; /* Complementary */
+  --accent-dark: #ffb275; /* Modified complementary */
+  --gray: 159, 140, 96; /* Inverted */
+  --gray-light: 26, 22, 15; /* Inverted */
+  --gray-dark: 221, 214, 198; /* Inverted */
+  --gray-gradient: rgba(26, 22, 15, 50%), #000; /* Adjusted */
+  --box-shadow: 0 -2px -6px rgba(159, 140, 96, 25%),
+    0 -8px -24px rgba(159, 140, 96, 33%), 0 -16px -32px rgba(159, 140, 96, 33%);
+}
+
+html {
+  background: var(--white);
+}
+
+/* fonts */
+@font-face {
+  font-family: "Atkinson";
+  src: url("/fonts/atkinson-regular.woff") format("woff");
+  font-weight: 400;
+  font-style: normal;
+  font-display: swap;
+}
+@font-face {
+  font-family: "Atkinson";
+  src: url("/fonts/atkinson-bold.woff") format("woff");
+  font-weight: 700;
+  font-style: normal;
+  font-display: swap;
+}
+/* Fonts */
+@font-face {
+  font-family: "Roboto";
+  src: url("/Roboto-Regular.ttf");
+}
+
+@font-face {
+  font-family: "Roboto Light";
+  src: url("/Roboto-Thin.ttf");
+}
+
+a {
+  color: inherit; /* blue colors for links too */
+  text-decoration: inherit; /* no underline */
+}
+
+body {
+  font-family: "Atkinson", sans-serif;
+  margin: 0;
+  padding: 0;
+  text-align: left;
+  background: var(--gray-gradient);
+  background-size: 100% 600px;
+  word-wrap: break-word;
+  overflow-wrap: break-word;
+  color: rgb(var(--gray-dark));
+  font-size: 20px;
+  line-height: 1.7;
+}
+main {
+  background: var(--white);
+  width: var(--main-width);
+  max-width: calc(100% - 2em);
+  margin: auto;
+  padding: 1em 1em;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  margin: 0 0 0.5rem 0;
+  color: rgb(var(--black));
+  line-height: 1.2;
+}
+h1 {
+  font-size: 3.052em;
+}
+h2 {
+  font-size: 2.441em;
+}
+h3 {
+  font-size: 1.953em;
+}
+h4 {
+  font-size: 1.563em;
+}
+h5 {
+  font-size: 1.25em;
+}
+strong,
+b {
+  font-weight: 700;
+}
+p {
+  margin-bottom: 1em;
+}
+.prose p {
+  margin-bottom: 2em;
+}
+textarea {
+  width: 100%;
+  font-size: 16px;
+}
+input {
+  font-size: 16px;
+}
+table {
+  width: 100%;
+}
+img {
+  max-width: 100%;
+  height: auto;
+  border-radius: 8px;
+}
+code {
+  padding: 2px 5px;
+  background-color: rgb(var(--gray-light));
+  border-radius: 2px;
+}
+pre {
+  padding: 1.5em;
+  border-radius: 8px;
+}
+pre > code {
+  all: unset;
+}
+blockquote {
+  border-left: 4px solid var(--accent);
+  padding: 0 0 0 20px;
+  margin: 0px;
+  font-size: 1.333em;
+}
+hr {
+  border: none;
+  border-top: 1px solid rgb(var(--gray-light));
+}
+@media (max-width: 720px) {
+  body {
+    font-size: 18px;
+  }
+  main {
+    padding: 1em;
+  }
+}
+
+.sr-only {
+  border: 0;
+  padding: 0;
+  margin: 0;
+  position: absolute !important;
+  height: 1px;
+  width: 1px;
+  overflow: hidden;
+  /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
+  clip: rect(1px 1px 1px 1px);
+  /* maybe deprecated but we need to support legacy browsers */
+  clip: rect(1px, 1px, 1px, 1px);
+  /* modern browsers, clip-path works inwards from each corner */
+  clip-path: inset(50%);
+  /* added line to stop words getting smushed together (as they go onto separate lines and some screen readers do not understand line feeds as a space */
+  white-space: nowrap;
+}
+
+.center {
+  display: flex;
+  justify-content: center;
+}
Binary file mrjunejune/pages/fonts/Roboto-Regular.ttf has changed
Binary file mrjunejune/pages/fonts/Roboto-Thin.ttf has changed
Binary file mrjunejune/pages/fonts/atkinson-bold.woff has changed
Binary file mrjunejune/pages/fonts/atkinson-regular.woff has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/pages/index.html	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,240 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <BaseHead title="Resume" description="June's resume" />
+    <link rel="stylesheet" href="base.css" />
+    <link rel="stylesheet" href="resume.css" />
+  </head>
+  <body>
+     <main>
+       <div>
+         <p>Hi, my name is Juntae, but most people call me <b>June</b>.</p>
+         <p>I am a software engineer with experience spanning a wide range of companies, from small startups to FAANG. </p> 
+         <p>Feel free to check out my <a href="/resume.pdf"> resume </a> below, and if you're interested, don’t hesitate to contact me for contract work ranging from web/app development to embedded programming.</p>
+       </div>
+       <div class="info">
+         <p><span class="header-firstname-style"> JUNTAE </span><span class="header-lastname-style">PARK</span><p>
+         <p class="header-position-style"> FULL STACK DEVELOPER · SOFTWARE ENGINEER </p>
+         <div class="header-address-style"> 
+           Bay Area, CA, USA
+         </div>
+         <div class="header-social-style">
+           <p>📱(US) 650-531-1728 |📱(CA) 437-580-8026 | <a href="mailto:[email protected]"> ✉️  [email protected] </a>| <a href="https://github.com/mrjunejune"> 
+                <svg viewBox="0 0 16 16" aria-hidden="true" width="12" height="12">
+                  <path
+						fill="currentColor"
+						d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"
+                        ></path>
+                </svg> mrjunejune
+           </a>| <a href="https://www.linkedin.com/in/junepark"> 
+              <svg width="12" height="12" fill="currentColor" class="bi bi-linkedin" viewBox="0 0 16 16">
+                <path d="M0 1.146C0 .513.526 0 1.175 0h13.65C15.474 0 16 .513 16 1.146v13.708c0 .633-.526 1.146-1.175 1.146H1.175C.526 16 0 15.487 0 14.854zm4.943 12.248V6.169H2.542v7.225zm-1.2-8.212c.837 0 1.358-.554 1.358-1.248-.015-.709-.52-1.248-1.342-1.248S2.4 3.226 2.4 3.934c0 .694.521 1.248 1.327 1.248zm4.908 8.212V9.359c0-.216.016-.432.08-.586.173-.431.568-.878 1.232-.878.869 0 1.216.662 1.216 1.634v3.865h2.401V9.25c0-2.22-1.184-3.252-2.764-3.252-1.274 0-1.845.7-2.165 1.193v.025h-.016l.016-.025V6.169h-2.4c.03.678 0 7.225 0 7.225z"/>
+              </svg>
+             junepark
+             </a>
+           </p>
+         </div>
+       </div>
+
+       <div class="sub-header">
+         <h2 class="section-style"> Summary </h2>
+         <div class="line"></div>
+       </div>
+       <p class="paragraph-style">Software Engineer with 8 years of hands-on experience across diverse tech stacks, from early-stage startups to FANG-scale systems. Adept in designing and delivering robust software solutions using modern languages, frameworks, and cloud platforms.  Open to impactful work.</p>
+       <div class="sub-header">
+
+         <h2 class="section-style"> Skills </h2>
+         <div class="line"></div>
+       </div>
+       <div class="paragraph-style">
+         <p>
+           <span class="entry-title-style"> Programming Languages:</span>
+           <span class="skill-type-style"> TypeScript, Python, C++/C, Ruby, Java, MATLAB </span>
+         </p>
+         <p> 
+           <span class="entry-title-style">Tools & Platforms:</span>
+           <span class="skill-type-style">Bazel, PostgresSQL, Mercurial, Git, Pands, Raylib, XCode</span>
+         </p>
+         <p>
+           <span class="entry-title-style"> Web Frameworks: </span>
+           <span class="skill-type-style"> Django, Rails, React, Flask</span>
+         </p>
+         <p>
+           <span class="entry-title-style"> DevOp:</span>
+           <span class="skill-type-style"> Plummi, Heroku, DigitalOcean, AWS, Google Cloud </span>
+         </p>
+         <p>
+           <span class="entry-title-style"> Language:</span>
+           <span class="skill-type-style"> English, Korean, Japanese </span>
+         </p>
+       </div>
+
+       <!-- Experiences -->
+      <div class="sub-header">
+         <h2 class="section-style"> Experience </h2>
+         <div class="line"></div>
+       </div>
+       <div class="flex-box">
+         <p class="entry-title-style">
+           <a href="https://www.meta.com/">Meta</a>
+         </p>
+         <p class="entry-location-style">San Francisco, CA, USA</p>
+       </div>
+       <div class="flex-box">
+         <p class="entry-position-style">SOFTWARE ENGINEER</p>
+         <p class="entry-date-style">Oct, 2024 - Present</p>
+       </div>
+         <ul class="description-style">
+           <li>
+             Took initiative on Channel Value Rule, targeting the 16% of ad traffic with both app and web destinations to improve value attribution and ROI.
+           </li>
+           <li>
+             Built full-stack features using React and Hack/GraphQL, contributing to scalable, production-ready systems.
+           </li>
+           <li>
+             Partnered with data science to design A/B tests and analyze revenue impact of ads destination.
+           </li>
+           <li>
+             Proposed and implemented alpha improvements to internal testing infrastructure, reducing test time by 50% and enhancing developer velocity.
+           </li>
+         </ul>
+       <div class="flex-box">
+         <p class="entry-title-style">
+           <a href="https://www.wmg.com/">Warner Music Group</a>
+         </p>
+         <p class="entry-location-style">Toronto, ON, Canada</p>
+       </div>
+       <div class="flex-box">
+         <p class="entry-position-style">TECHNICAL LEAD ENGINEER</p>
+         <p class="entry-date-style">July, 2023 - Sept, 2024</p>
+       </div>
+       <ul class="description-style">
+         <li>
+           Implements <a href="https://bazel.build/">bazel </a>structure for the company for TypeScript and JavaScript code base for hermiticity and stablishing standards for JavaScript and
+         </li>
+         <li>
+           TypeScript testing and code structures.
+         </li>
+         <li>
+           Led a team of five engineers in building GraphQL endpoints for client-facing applications using Apollo and AppSync, supporting over 2000 RPS and auto scaling depending on request values.
+         </li>
+         <li>
+           Improved application response times by up to 85% for graphQL response by updating database schema and SQL queries, eliminating N+1 queries and lack of indexes.
+         </li>
+         <li>
+           Developed CI/CD pipelines for backend structures.
+         </li>
+         <li>
+           Designed infrastructure for pub/sub, caching, and media processing logic.
+         </li>
+       </ul>
+
+       <div class="flex-box">
+         <p class="entry-title-style">
+           <a href="https://www.google.com/">Google</a>
+         </p>
+         <p class="entry-location-style">Toronto, ON, Canada</p>
+       </div>
+       <div class="flex-box">
+         <p class="entry-position-style">SOFTWARE ENGINEER</p>
+         <p class="entry-date-style">Feb, 2022 - July 2023</p>
+       </div>
+       <ul class="description-style">
+         <li>
+           Implements and maintained new features relating to App Script across google workspace platform including Gmail, sheets, and Docs.</li>
+         <li>
+           Improved a response time and render time of App Script hover card components.</li>
+         <li>
+           Collaborated with a team of developers to ensure timely and accurate delivery of features.</li>
+         <li>
+           Conducted user testing and gathered feedback to iterate on features for optimal user experience.</li>
+       </ul>
+
+       <div class="flex-box">
+         <p class="entry-title-style">
+           <a href="https://www.everlywell.com/">Everlywell</a>
+         </p>
+         <p class="entry-location-style">Toronto, ON, Canada</p>
+       </div>
+       <div class="flex-box">
+         <p class="entry-position-style">SOFTWARE ENGINEER</p>
+         <p class="entry-date-style">December, 2020 - Jan, 2022</p>
+       </div>
+       <ul class="description-style">
+         <li>
+           Maintained Amazon amplify apps to create and deploy React web applications for companies such as <a href="https://brooklynnets.everlywell.com/">NBA</a>, <a href="https://tinder.everlywell.com/">Tinder</a>, and other companies for COVID-19 at-home test kits.</li>
+         <li>
+           Implemented a script that helps accurately access and refund unused covid test kits; helping company save up to 200,000 USD.</li>
+         <li>
+           Created several Rails controllers for internal purposes; mocking end to end user experience for QA, mass refund features for CX department, and more, ultimately reducing support tickets amount by 50 percent.</li>
+         <li>
+           Implemented an audit table to help debug problems and logged which process was responsible for the change of the record using PaperTrail gems</li>
+       </ul>
+
+       <div class="flex-box">
+         <p class="entry-title-style">
+           <a href="https://www.spiria.com/">Spiria</a>
+         </p>
+         <p class="entry-location-style">Oakville, ON, Canada</p>
+       </div>
+       <div class="flex-box">
+         <p class="entry-position-style">SOFTWARE ENGINEER</p>
+         <p class="entry-date-style">October, 2018 - October, 2020</p>
+       </div>
+       <ul class="description-style">
+         <li>
+           Constructed RESTful API endpoints in multiple different frameworks such as Django, Ruby on Rails, and Flask and automated API documentation process using swagger.
+         </li>
+         <li>
+           Designed custom rake tasks for importing production data into newly updated data structure to meet client's needs.
+         </li>
+         <li>
+           Maintained or updated staging/productions servers. Debugged problems in production postgres database using ssh and postgres console on Heroku or AWS servers
+         </li>
+         <li>
+           Collaborated in creating automation python scripts for websites and application using selenium covering for QA eliminating 80% of QA's manual work
+         </li>
+       </ul>
+
+       <div class="flex-box">
+         <p class="entry-title-style">
+           <a href="https://www.apexscore.ai/">Apex Score</a>
+         </p>
+         <p class="entry-location-style">Oakville, ON, Canada</p>
+       </div>
+       <div class="flex-box">
+         <p class="entry-position-style">SOFTWARE ENGINEER</p>
+         <p class="entry-date-style">September, 2019 - October, 2020</p>
+       </div>
+       <ul class="description-style">
+         <li>
+           Developed custom Shapley value regression model to calculate importance of independent variables of data sets using sklearn, pandas, and numpy.
+         </li>
+         <li>
+           Created custom image uploader to Amazon s3 bucket using boto3 library.
+         </li>
+         <li>
+           Built RESTful API application using Flask framework and automated extensive API documentation pages using flask-restplus, pytest, and swagger, covering 95% of the code base.
+         </li>
+         <li>
+           Created an interactive graph using D3.js in Vue.js with data from Flask backend API. 
+         </li>
+       </ul>
+
+      <div class="sub-header">
+         <h2 class="section-style"> Education </h2>
+         <div class="line"></div>
+       </div>
+       <div class="flex-box">
+         <p class="entry-title-style">
+           University of British Columbia
+         </p>
+         <p class="entry-location-style">Kelowna, British Columbia</p>
+       </div>
+       <div class="flex-box">
+         <p class="entry-position-style">BACHELOR OF SCIENCE IN PHYSICS</p>
+         <p class="entry-date-style">2014 - 2018</p>
+       </div>
+     </main>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/pages/resume.css	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,161 @@
+:root {
+  --text: var(--black);
+  --graytext: var(--gray);
+  --lighttext: var(--lightgray);
+}
+
+.sub-header {
+  display: flex;
+  margin-top: 20px;
+  align-items: center;
+  gap: 5px;
+}
+
+.line {
+  flex-grow: 1;
+  border-bottom: 1px solid #333; /* Adjust color and thickness as needed */
+}
+
+.header-firstname-style {
+    font-size: 32pt;
+    font-family: "Roboto Light", sans-serif;
+    color: var(--graytext);
+}
+
+.header-lastname-style {
+    font-size: 32pt;
+    font-family: "Roboto", sans-serif;
+    font-weight: bold;
+    color: var(--text);
+}
+
+.header-position-style {
+    font-size: 7.6pt;
+    font-family: "Source Sans Pro", sans-serif;
+    font-variant: small-caps;
+    color: var(--awesome);
+}
+
+.header-address-style {
+    font-size: 8pt;
+    font-family: "Roboto", sans-serif;
+    font-style: italic;
+    color: var(--lighttext);
+}
+
+.header-social-style {
+    font-size: 10pt;
+    font-family: "Roboto", sans-serif;
+    color: var(--text);
+}
+
+.header-quote-style {
+    font-size: 9pt;
+    font-family: "Source Sans Pro", sans-serif;
+    font-style: italic;
+    color: var(--darktext);
+}
+
+.footer-style {
+    font-size: 8pt;
+    font-family: "Source Sans Pro", sans-serif;
+    font-variant: small-caps;
+    color: var(--lighttext);
+}
+
+.section-style {
+    font-size: 16pt;
+    font-family: "Source Sans Pro", sans-serif;
+    font-weight: bold;
+    color: var(--text);
+}
+
+.subsection-style {
+    font-size: 12pt;
+    font-family: "Source Sans Pro", sans-serif;
+    font-variant: small-caps;
+    color: var(--text);
+}
+
+.paragraph-style {
+    font-size: 9pt;
+    font-family: "Source Sans Pro Light", sans-serif;
+    color: var(--text);
+}
+
+.entry-title-style {
+    font-size: 10pt;
+    font-family: "Source Sans Pro", sans-serif;
+    font-weight: bold;
+    color: var(--darktext);
+}
+
+.entry-position-style {
+    font-size: 8pt;
+    font-family: "Source Sans Pro", sans-serif;
+    font-variant: small-caps;
+    color: var(--graytext);
+}
+
+.entry-date-style {
+    font-size: 8pt;
+    font-family: "Source Sans Pro Light", sans-serif;
+    font-style: italic;
+    color: var(--graytext);
+}
+
+.entry-location-style {
+    font-size: 9pt;
+    font-family: "Source Sans Pro Light", sans-serif;
+    font-style: italic;
+    color: var(--awesome);
+}
+
+.description-style {
+    font-size: 9pt;
+    font-family: "Source Sans Pro Light", sans-serif;
+    color: var(--text);
+}
+
+.subentry-title-style {
+    font-size: 8pt;
+    font-family: "Source Sans Pro", sans-serif;
+    color: var(--graytext);
+}
+
+.subentry-position-style {
+    font-size: 7pt;
+    font-family: "Source Sans Pro", sans-serif;
+    font-variant: small-caps;
+    color: var(--graytext);
+}
+
+.honor-title-style,
+.honor-position-style,
+.honor-date-style,
+.honor-location-style,
+.skill-type-style,
+.skill-set-style {
+    font-size: 9pt;
+    font-family: "Source Sans Pro", sans-serif;
+    color: var(--graytext);
+}
+
+.letter-section-style,
+.recipient-title-style,
+.letter-title-style,
+.letter-date-style,
+.letter-text-style,
+.letter-name-style,
+.letter-enclosure-style {
+    font-family: "Source Sans Pro", sans-serif;
+}
+
+.info {
+  text-align: center;
+}
+
+.flex-box {
+  display: flex;
+  justify-content: space-between;
+}
--- a/seobeo/BUILD	Mon Sep 29 16:00:44 2025 -0700
+++ b/seobeo/BUILD	Mon Sep 29 17:00:38 2025 -0700
@@ -1,12 +1,14 @@
 load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
 load("@rules_cc//cc:cc_library.bzl", "cc_library")
 
-alias(
-  name = "seobeo",
-  actual = select({
-    "@platforms//os:osx": ":seobeo_example_mac",
-  }),
-  visibility = ["//visibility:public"],
+config_setting(
+  name        = "macos",
+  constraint_values = ["@platforms//os:osx"],
+)
+
+config_setting(
+  name        = "linux",
+  constraint_values = ["@platforms//os:linux"],
 )
 
 filegroup(
@@ -18,35 +20,55 @@
   name = "seobeo_headers",
   srcs = [
     "seobeo.h",
-    "seobeo_internal.h"
+    "seobeo_internal.h",
   ],
   visibility = ["//visibility:public"],
 )
 
 cc_binary(
-  name = "seobeo_example_mac",
+  name = "seobeo_example",
   srcs = ["main.c"],
-  deps = [":seobeo_non_window"],
-  data = glob(["pages/**"]),
+  deps = [":seobeo"],
+  data = [":pages_files"],
+)
+
+alias(
+  name   = "seobeo",
+  actual = select({
+    ":macos":  ":seobeo_macos",
+    ":linux":  ":seobeo_linux",
+    "//conditions:default": ":seobeo_linux",
+  }),
+  visibility = ["//visibility:public"],
+)
+
+cc_library(
+  name = "seobeo_macos",
+  srcs = [
+    "s_linux_network.c",
+    "s_web.c",
+    "os/s_macos_edge.c",
+  ],
+  hdrs = [":seobeo_headers"],
+  deps = ["//dowa:dowa"],
   target_compatible_with = [
-      "@platforms//os:osx",
+    "@platforms//os:osx",
   ],
   visibility = ["//visibility:public"],
 )
 
 cc_library(
-  name = "seobeo_non_window",
+  name = "seobeo_linux",
   srcs = [
     "s_linux_network.c",
     "s_web.c",
+    "os/s_linux_edge.c",
   ],
+  hdrs = [":seobeo_headers"],
   deps = ["//dowa:dowa"],
-  hdrs = [
-    "seobeo.h",
-    "seobeo_internal.h"
-  ],
   target_compatible_with = [
-      "@platforms//os:osx",
+    "@platforms//os:linux",
   ],
   visibility = ["//visibility:public"],
 )
+
--- a/seobeo/example.c	Mon Sep 29 16:00:44 2025 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-/*
-** server.c -- a stream socket server demo
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <sys/wait.h>
-#include <signal.h>
-
-#define PORT "3490"  // the port users will be connecting to
-
-#define BACKLOG 10   // how many pending connections queue will hold
-
-void sigchld_handler(int s)
-{
-    (void)s; // quiet unused variable warning
-
-    // waitpid() might overwrite errno, so we save and restore it:
-    int saved_errno = errno;
-
-    while(waitpid(-1, NULL, WNOHANG) > 0);
-
-    errno = saved_errno;
-}
-
-
-// get sockaddr, IPv4 or IPv6:
-void *get_in_addr(struct sockaddr *sa)
-{
-    if (sa->sa_family == AF_INET) {
-        return &(((struct sockaddr_in*)sa)->sin_addr);
-    }
-
-    return &(((struct sockaddr_in6*)sa)->sin6_addr);
-}
-
-int main(void)
-{
-    // listen on sock_fd, new connection on new_fd
-    int sockfd, new_fd;
-    struct addrinfo hints, *servinfo, *p;
-    struct sockaddr_storage their_addr; // connector's address info
-    socklen_t sin_size;
-    struct sigaction sa;
-    int yes=1;
-    char s[INET6_ADDRSTRLEN];
-    int rv;
-
-    memset(&hints, 0, sizeof hints);
-    hints.ai_family = AF_INET;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = AI_PASSIVE; // use my IP
-
-    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
-        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
-        return 1;
-    }
-
-    // loop through all the results and bind to the first we can
-    for(p = servinfo; p != NULL; p = p->ai_next) {
-        if ((sockfd = socket(p->ai_family, p->ai_socktype,
-                p->ai_protocol)) == -1) {
-            perror("server: socket");
-            continue;
-        }
-
-        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
-                sizeof(int)) == -1) {
-            perror("setsockopt");
-            exit(1);
-        }
-
-        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
-            close(sockfd);
-            perror("server: bind");
-            continue;
-        }
-
-        break;
-    }
-
-    freeaddrinfo(servinfo); // all done with this structure
-
-    if (p == NULL)  {
-        fprintf(stderr, "server: failed to bind\n");
-        exit(1);
-    }
-
-    if (listen(sockfd, BACKLOG) == -1) {
-        perror("listen");
-        exit(1);
-    }
-
-    sa.sa_handler = sigchld_handler; // reap all dead processes
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESTART;
-    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
-        perror("sigaction");
-        exit(1);
-    }
-
-    printf("server: waiting for connections...\n");
-
-    while(1) {  // main accept() loop
-        sin_size = sizeof their_addr;
-        new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
-            &sin_size);
-        if (new_fd == -1) {
-            perror("accept");
-            continue;
-        }
-
-        inet_ntop(their_addr.ss_family,
-            get_in_addr((struct sockaddr *)&their_addr),
-            s, sizeof s);
-        printf("server: got connection from %s\n", s);
-
-        char *yo = "HTTP/1.1 OK %s\r\n"
-                 "Content-Type: text/txt\r\n"
-                 "Content-Length: 13\r\n"
-                 "Connection: close\r\n"
-                 "\r\n"
-                 "Hello, world!";
-
-        if (!fork()) { // this is the child process
-            close(sockfd); // child doesn't need the listener
-            if (send(new_fd, 
-                 "HTTP/1.1 OK %s\r\n"
-                 "Content-Type: text/txt\r\n"
-                 "Content-Length: 13\r\n"
-                 "Connection: close\r\n"
-                 "\r\n"
-                 "Hello, world!"
-                , strlen(yo), 0) == -1)
-                perror("send");
-            close(new_fd);
-            exit(0);
-        }
-        close(new_fd);  // parent doesn't need this
-    }
-
-    return 0;
-}
--- a/seobeo/main.c	Mon Sep 29 16:00:44 2025 -0700
+++ b/seobeo/main.c	Mon Sep 29 17:00:38 2025 -0700
@@ -7,5 +7,5 @@
 
 int main(void)
 {
-  Seobeo_Web_StartBasicHTTPServer("seobeo/pages", "8080");
+  Seobeo_Web_StartBasicHTTPServer("seobeo/pages", "8080", SEOBEO_MODE_FORK, 2);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/seobeo/os/s_linux_edge.c	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,66 @@
+#include <sys/epoll.h>
+#include "seobeo/seobeo.h"
+
+
+void  *Seobeo_Web_Edge_Worker(void *vargs)
+{
+  WorkerArgs *args = vargs;
+  struct epoll_event events[64];
+  while (1) {
+    int n = epoll_wait(args->evfd, events, 64, -1);
+    if (n < 0) continue;
+    for (int i = 0; i < n; i++) {
+      Seobeo_PHandle h = events[i].data.ptr;
+      if (h == args->srv) {
+        // new connection
+        Seobeo_PHandle cli =
+          Seobeo_Stream_Handle_Accept(args->srv);
+        if (!cli) continue;
+        struct epoll_event ev = {
+          .events   = EPOLLIN,
+          .data.ptr = cli
+        };
+        epoll_ctl(args->evfd, EPOLL_CTL_ADD,
+                  cli->socket, &ev);
+      } else {
+        // client ready
+        Seobeo_Web_HandleClientRequest(h, args->cache);
+        epoll_ctl(args->evfd, EPOLL_CTL_DEL,
+                  h->socket, NULL);
+        Seobeo_Handle_Destroy(h);
+      }
+    }
+  }
+  return NULL;
+}
+
+void  Seobeo_Web_Edge(
+    Seobeo_PHandle p_server_handle,
+    int            thread_count,
+    Dowa_PHashMap   p_html_cache)
+{
+  int epfd = epoll_create1(0);
+  struct epoll_event ev = {
+    .events   = EPOLLIN,
+    .data.ptr = p_server_handle
+  };
+  epoll_ctl(epfd, EPOLL_CTL_ADD,
+            p_server_handle->socket, &ev);
+
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setstacksize(&attr, 100 * 1024 * 1024); // 100 MB
+
+  pthread_t  threads[thread_count];
+  WorkerArgs args = { p_server_handle, p_html_cache, epfd };
+  for (int i = 0; i < thread_count; i++)
+  {
+    pthread_create(&threads[i], NULL,
+                   Seobeo_Web_Edge_Worker, &args);
+  }
+  for (int i = 0; i < thread_count; i++)
+  {
+    pthread_join(threads[i], NULL);
+  }
+  return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/seobeo/os/s_macos_edge.c	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,70 @@
+#include <sys/event.h>
+#include "seobeo/seobeo.h"
+
+
+void *Seobeo_Web_Edge_Worker(void *vargs)
+{
+  WorkerArgs *args = vargs;
+  struct kevent evlist[64];
+  while (1) {
+    int ne = kevent(args->evfd, NULL, 0, evlist, 64, NULL);
+    if (ne < 0) continue;
+    for (int i = 0; i < ne; i++) {
+      Seobeo_PHandle h = evlist[i].udata;
+      if (h == args->srv) {
+        Seobeo_PHandle cli =
+          Seobeo_Stream_Handle_Accept(args->srv);
+        if (!cli) continue;
+        struct kevent kev = {
+          .ident  = cli->socket,
+          .filter = EVFILT_READ,
+          .flags  = EV_ADD,
+          .udata  = cli
+        };
+        kevent(args->evfd, &kev, 1, NULL, 0, NULL);
+      } else {
+        Seobeo_Web_HandleClientRequest(h, args->cache);
+        struct kevent kev = {
+          .ident  = h->socket,
+          .filter = EVFILT_READ,
+          .flags  = EV_DELETE,
+        };
+        kevent(args->evfd, &kev, 1, NULL, 0, NULL);
+        Seobeo_Handle_Destroy(h);
+      }
+    }
+  }
+  return NULL;
+}
+
+void  Seobeo_Web_Edge(
+    Seobeo_PHandle p_server_handle,
+    int            thread_count,
+    Dowa_PHashMap  p_html_cache)
+{
+  int kq = kqueue();
+  struct kevent kev = {
+    .ident  = p_server_handle->socket,
+    .filter = EVFILT_READ,
+    .flags  = EV_ADD,
+    .udata  = p_server_handle
+  };
+  kevent(kq, &kev, 1, NULL, 0, NULL);
+
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setstacksize(&attr, 100 * 1024 * 1024); // 100 MB
+
+  pthread_t  threads[thread_count];
+  WorkerArgs args = { p_server_handle, p_html_cache, kq };
+  for (int i = 0; i < thread_count; i++)
+  {
+    pthread_create(&threads[i], NULL,
+                   Seobeo_Web_Edge_Worker, &args);
+  }
+  for (int i = 0; i < thread_count; i++)
+  {
+    pthread_join(threads[i], NULL);
+  }
+  return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/seobeo/pages/hello/bar.txt	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,1 @@
+hello
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/seobeo/pages/hello/index.html	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,8 @@
+<HTML>
+  <head>
+    <script src="index.js"></script>
+  </head>
+  <body>
+    <h1> Hello </h1>
+  </body>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/seobeo/pages/hello/index.js	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,1 @@
+console.log("Hello 2");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/seobeo/pages/index.js	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,1 @@
+console.log("hello");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/seobeo/s_web.c	Mon Sep 29 17:00:38 2025 -0700
@@ -0,0 +1,304 @@
+#include "seobeo/seobeo.h"
+
+void Seobeo_Web_GenerateResponseHeader(void *buffer, int status,
+                                       const char *content_type, const int content_length) 
+{
+  const char *status_text;
+  switch(status)
+  {
+    case HTTP_OK: status_text = "OK"; break;
+    case HTTP_CREATED: status_text = "Created"; break;
+    case HTTP_MOVED_PERMANENTLY: status_text = "Moved Permanently"; break;
+    case HTTP_FOUND: status_text = "Found"; break;
+    case HTTP_BAD_REQUEST: status_text = "Bad Request"; break;
+    case HTTP_UNAUTHORIZED: status_text = "Unauthorized"; break;
+    case HTTP_FORBIDDEN: status_text = "Forbidden"; break;
+    case HTTP_NOT_FOUND: status_text = "Not Found"; break;
+    case HTTP_INTERNAL_ERROR: status_text = "Internal Server Error"; break;
+    default: status_text = "Unknown"; break;
+  }
+  
+  sprintf(
+    buffer, 
+    "HTTP/2.2 %d %s\r\n"
+    "Content-Type: %s\r\n"
+    "Content-Length: %d\r\n"
+    "Connection: close\r\n"
+    "\r\n", 
+    status, status_text, content_type, content_length
+  );
+}
+
+void Seobeo_Web_HandleClientRequest(Seobeo_PHandle p_cli_handle,
+                                    Dowa_PHashMap p_html_cache)
+{
+  Dowa_PArena p_response_arena = Dowa_Arena_Create(8192);
+  Dowa_PHashMap p_req_map = NULL;
+
+  Dowa_PHashEntry entry = NULL;
+  Dowa_PHashMap p_current = p_html_cache;
+  char *slash;
+
+  if (!p_response_arena) { perror("Dowa_Arena_Initialize"); goto clean_up; }
+
+  void *p_response_header = Dowa_Arena_Allocate(p_response_arena, (size_t)2048);
+  if (!p_response_header) { perror("Dowa_Arena_Allocate"); goto clean_up; }
+
+  p_req_map = Dowa_HashMap_Create(32);
+  if (Seobeo_Web_ParseClientHeader(p_cli_handle, p_req_map) != 0)
+  {
+    // malformed request or closed — respond 400
+    Seobeo_Web_GenerateResponseHeader(p_response_header,
+                                      HTTP_BAD_REQUEST,
+                                      "text/plain", 0);
+    Seobeo_Handle_Queue(p_cli_handle,
+                (const uint8*)p_response_header,
+                (uint32)strlen(p_response_header));
+    Seobeo_Handle_Flush(p_cli_handle);
+    goto clean_up;
+  }
+
+  const char *path = (const char*)Dowa_HashMap_Get(p_req_map, "Path");
+
+  char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)512);
+
+  if (!path || strcmp(path, "/") == 0)
+  {
+    strcpy(file_path, "index.html");
+  }
+  else
+  {
+    size_t L = strlen(path);
+    // strip leading '/'
+    if (path[0] == '/')
+    {
+      if (strchr(path, '.') == NULL)
+        snprintf(file_path, 512, "%.*s/index.html", (int)(L-1), path+1);
+      else
+        snprintf(file_path, 512, "%.*s", (int)(L-1), path+1);
+    }
+    else
+    {
+      // Probably never get here?
+      strcpy(file_path, path);
+    }
+  }
+
+  // printf("\n\nfile_path: %s\n", file_path);
+
+  // Recursively go though the path until it gets to a file
+  while ((slash = strchr(file_path, '/')))
+  {
+    *slash = '\0'; // e.g. file_path="foo", slash+1="index.html"
+    char *dir     = file_path; // "foo"
+    file_path = slash + 1;  // "index.html"
+
+    p_current = Dowa_HashMap_Get(p_current, dir);
+    if (!p_current) { perror("No value"); goto clean_up; }
+  }
+
+  size_t pos = Dowa_HashMap_GetPosition(p_current, file_path);
+  entry = p_current->entries[pos];
+
+  //  Missing so 404
+  if (!entry)
+  {
+    Seobeo_Web_GenerateResponseHeader(p_response_header,
+                                      HTTP_NOT_FOUND,
+                                      "text/html", 0);
+    Seobeo_Handle_Queue(p_cli_handle,
+                (const uint8*)p_response_header,
+                (uint32)strlen(p_response_header));
+    Seobeo_Handle_Flush(p_cli_handle);
+    goto clean_up;
+  }
+
+
+  const char *mime = "application/octet-stream"; // Default binary
+  if (strstr(file_path, ".html")) mime = "text/html; charset=utf-8";
+  else if (strstr(file_path, ".css")) mime = "text/css";
+  else if (strstr(file_path, ".js")) mime = "application/javascript";
+  else if (strstr(file_path, ".png")) mime = "image/png";
+  else if (strstr(file_path, ".jpg") || strstr(file_path, ".jpeg")) mime = "image/jpeg";
+  else if (strstr(file_path, ".gif")) mime = "image/gif";
+  else if (strstr(file_path, ".svg")) mime = "image/svg+xml";
+  else if (strstr(file_path, ".ico")) mime = "image/x-icon";
+  else if (strstr(file_path, ".json")) mime = "application/json";
+
+  size_t body_size = entry->capacity;
+  Seobeo_Web_GenerateResponseHeader(p_response_header,
+                                    HTTP_OK,
+                                    mime,
+                                    body_size);
+  Seobeo_Handle_Queue(p_cli_handle,
+              (const uint8*)p_response_header,
+              (uint32)strlen(p_response_header));
+  Seobeo_Handle_Queue(p_cli_handle,
+              (const uint8*)entry->buffer,
+              (uint32)body_size);
+  Seobeo_Handle_Flush(p_cli_handle);
+
+clean_up:
+  Seobeo_Handle_Destroy(p_cli_handle);
+  Dowa_Arena_Free(p_response_arena);
+  Dowa_HashMap_Free(p_req_map); // TODO: Maybe initilized hashmap within the Arena?  
+}
+
+int Seobeo_Web_ParseClientHeader(Seobeo_PHandle p_handle, Dowa_PHashMap map)
+{
+  // 1) Fill read_buffer until we see "\r\n\r\n"
+  while (1)
+  {
+    int r = Seobeo_Handle_Read(p_handle);
+    if (r < 0)   return -1;   // fatal error
+    if (r == -2) return -2;   // connection closed TODO: Add this as part of Handle struct.
+
+    if (p_handle->read_buffer_len >= 4 &&
+        strstr((char*)p_handle->read_buffer, "\r\n\r\n") != NULL)
+    {
+      break;
+    }
+    if (r == 0) return 1;     // EAGAIN, try again later TODO: Add this as part of Handle struct.
+  }
+
+  // 2) Parse request‐line "METHOD SP PATH SP VERSION CRLF"
+  char *buf       = (char*)p_handle->read_buffer;
+  char *hdr_end   = strstr(buf, "\r\n\r\n");
+  size_t hdr_len  = hdr_end - buf + 4;
+
+  char method[16], path[256], version[16];
+  if (sscanf(buf, "%15s %255s %15s", method, path, version) != 3)
+  {
+    return -1;
+  }
+
+  Dowa_HashMap_PushValueWithType(map, "Method",  method,  strlen(method)  + 1, DOWA_HASH_MAP_TYPE_STRING);
+  Dowa_HashMap_PushValueWithType(map, "Path",    path,    strlen(path)    + 1, DOWA_HASH_MAP_TYPE_STRING);
+  Dowa_HashMap_PushValueWithType(map, "Version", version, strlen(version) + 1, DOWA_HASH_MAP_TYPE_STRING);
+
+  // 3) Parse each header line until the blank line
+  char *line = buf + strlen(method) + 1 + strlen(path) + 1 + strlen(version) + 2;
+  while (line < hdr_end)
+  {
+    char *next = strstr(line, "\r\n");
+    if (!next) break;
+
+    // split at colon
+    char *colon = memchr(line, ':', next - line);
+    if (colon) {
+      size_t key_len   = colon - line;
+      size_t value_len = next - colon - 1;
+
+      char *val_start  = colon + 1;
+      if (*val_start == ' ')
+      {
+        val_start++;
+        value_len--;
+      }
+
+      char *key = malloc(key_len + 1);
+      memcpy(key, line, key_len);
+      key[key_len] = '\0';
+
+      char *val = malloc(value_len + 1);
+      memcpy(val, val_start, value_len);
+      val[value_len] = '\0';
+
+      Dowa_HashMap_PushValue(map, key, val, value_len + 1);
+
+      free(key);
+      free(val);
+    }
+
+    line = next + 2;
+  }
+  Seobeo_Handle_Consume(p_handle, (uint32)hdr_len);
+
+  // 4) If Content-Length was provided, read that much body
+  int content_length_pos = Dowa_HashMap_GetPosition(map, "Content-Length");
+  Dowa_PHashEntry p_content_length_entry = map->entries[content_length_pos];
+  if (p_content_length_entry)
+  {
+    size_t body_len = atoi((char*)p_content_length_entry->buffer);
+    while (p_handle->read_buffer_len < body_len)
+    {
+      int r = Seobeo_Handle_Read(p_handle);
+      if (r < 0)   return -1;
+      if (r ==  0) return 1;       // wait for more data
+    }
+
+    char *body = malloc(body_len + 1);
+    memcpy(body, p_handle->read_buffer, body_len);
+    body[body_len] = '\0';
+
+    Dowa_HashMap_PushValue(map, "Body", body, body_len + 1);
+    free(body);
+
+    Seobeo_Handle_Consume(p_handle, (uint32)body_len);
+  }
+
+  return 0;  // success; map now holds Method, Path, Version, headers, and optional Body
+}
+
+//  TODO: Do epoll or kqueue depending on the OS.
+void SigchildHandler(int s)
+{
+  (void)s; // quiet unused variable warning
+
+  // waitpid() might overwrite errno, so we save and restore it:
+  int saved_errno = errno;
+
+  while(waitpid(-1, NULL, WNOHANG) > 0);
+
+  errno = saved_errno;
+}
+
+int Seobeo_Web_StartBasicHTTPServer(
+    const char       *folder_path,
+    const char       *port,
+    Seobeo_ServerMode mode,
+    int                thread_count)
+{
+  Dowa_PHashMap p_html_cache = Dowa_HashMap_Create(1024);
+  if (Dowa_HashMap_Cache_Folder(p_html_cache,
+                                folder_path) != 0)
+  {
+    perror("Dowa_Cache_Folder");
+    return -1;
+  }
+
+  Seobeo_PHandle p_server_handle =
+    Seobeo_Stream_Handle_Create(NULL, port);
+  if (p_server_handle->socket < 0) return 1;
+  printf("Listening on port %s\n", port);
+
+  // Fork‐based fallback
+  if (mode == SEOBEO_MODE_FORK)
+  {
+    struct sigaction sa;
+    sa.sa_handler = SigchildHandler;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_RESTART;
+    sigaction(SIGCHLD, &sa, NULL);
+
+    while (1) {
+      Seobeo_PHandle cli =
+        Seobeo_Stream_Handle_Accept(p_server_handle);
+      if (!cli) continue;
+
+      if (fork() == 0) {
+        Seobeo_Web_HandleClientRequest(cli,
+                                       p_html_cache);
+        _exit(0);
+      }
+      Seobeo_Handle_Destroy(cli);
+    }
+  }
+
+  if (mode == SEOBEO_MODE_EDGE)
+  {
+    Seobeo_Web_Edge(p_server_handle, thread_count, p_html_cache);
+  }
+
+  return -1;
+}
--- a/seobeo/seobeo.h	Mon Sep 29 16:00:44 2025 -0700
+++ b/seobeo/seobeo.h	Mon Sep 29 17:00:38 2025 -0700
@@ -18,6 +18,7 @@
 #include <sys/wait.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <pthread.h>
 
 #include "dowa/dowa.h"
 
@@ -53,6 +54,16 @@
   char    *file_name;
 } Sebeo_Handle, *Seobeo_PHandle;
 
+typedef struct {
+  Seobeo_PHandle  srv;
+  Dowa_PHashMap   cache;
+  int             evfd;    // epoll‐fd or kqueue‐fd
+} WorkerArgs;
+
+typedef enum {
+  SEOBEO_MODE_FORK,
+  SEOBEO_MODE_EDGE,
+} Seobeo_ServerMode;
 
 // --- Socket, IP related --- //
 extern int            Seobeo_CreateSocket(int32 stream, const char *host,  const char* port, int32 backlog);
@@ -67,7 +78,9 @@
 extern void           Seobeo_Web_GenerateResponseHeader(void *buffer, int status, const char *content_type, const int content_length);
 extern void           Seobeo_Web_HandleClientRequest(Seobeo_PHandle cli, Dowa_PHashMap p_html_cache);
 extern int            Seobeo_Web_ParseClientHeader(Seobeo_PHandle p_handle, Dowa_PHashMap map);
-extern int            Seobeo_Web_StartBasicHTTPServer(const char *folder_path, const char *port);
+extern int            Seobeo_Web_StartBasicHTTPServer(const char *folder_path, const char *port, Seobeo_ServerMode mode, int thread_count);
+extern void           *Seobeo_Web_Edge_Worker(void *vargs); // Maybe not web only...
+extern void           Seobeo_Web_Edge(Seobeo_PHandle p_server_handle, int thread_count, Dowa_PHashMap p_html_cache);
 
 // --- Helper functions --- //
 extern void           Seobeo_Handle_Destroy(Seobeo_PHandle p_handle);