changeset 94:092afa595764

[MrJuneJune] Added Integration tests.
author June Park <parkjune1995@gmail.com>
date Fri, 02 Jan 2026 18:13:32 -0800
parents be91a73d801a
children b51f8cce9170
files mrjunejune/BUILD mrjunejune/test/README.md mrjunejune/test/create_snapshots.c mrjunejune/test/integration_test.c mrjunejune/test/shiba.webp mrjunejune/test/snapshots/index.html.snapshot mrjunejune/test/snapshots/resume.snapshot mrjunejune/test/snapshots/resume_index.html.snapshot mrjunejune/test/snapshots/root.snapshot mrjunejune/test/snapshots/tools.snapshot mrjunejune/test/snapshots/tools_file_converter.snapshot mrjunejune/test/snapshots/tools_file_converter_index.html.snapshot mrjunejune/test/snapshots/tools_index.html.snapshot mrjunejune/test/snapshots/tools_markdown_to_html.snapshot mrjunejune/test/snapshots/tools_markdown_to_html_index.html.snapshot mrjunejune/test/test_avi.avi
diffstat 16 files changed, 3067 insertions(+), 487 deletions(-) [+]
line wrap: on
line diff
--- a/mrjunejune/BUILD	Fri Jan 02 18:02:22 2026 -0800
+++ b/mrjunejune/BUILD	Fri Jan 02 18:13:32 2026 -0800
@@ -37,24 +37,6 @@
   binary = ":mrjunejune_server",
 )
 
-cc_library(
-  name = "mrjunejune_server_lib",
-  srcs = ["server_entry.c"],
-  deps = ["//seobeo:seobeo_server"],  # Use server-only target (no OpenSSL)
-  linkstatic = False,   # ensures dynamic linking
-  visibility = ["//visibility:public"],
-)
-
-# py_binary(
-#   name = "python_server",
-#   srcs = ["python_server.py"],
-#   deps = [
-#     ":mrjunejune_server_lib",
-#     "@pip_deps//:cffi",
-#   ],
-#   data = [":mrjunejune_server_lib"],
-# )
-
 cc_test(
   name = "integration_test",
   srcs = ["test/integration_test.c"],
@@ -63,9 +45,10 @@
     "//mrjunejune:mrjunejune_server",
     "//mrjunejune:src_files",
     "//mrjunejune:test_snapshots",
+    "//mrjunejune:test_files",
   ],
-  size = "medium",
-  timeout = "moderate",
+  size = "large",
+  timeout = "long",
   args = ["$(location //mrjunejune:mrjunejune_server)"],
 )
 
@@ -84,3 +67,32 @@
   name = "test_snapshots",
   srcs = glob(["test/snapshots/**"]),
 )
+
+filegroup(
+  name = "test_files",
+  srcs = [
+    "test/shiba.webp",
+    "test/test_avi.avi",
+  ],
+)
+
+# This was to use python ffi, but w/e
+# cc_library(
+#   name = "mrjunejune_server_lib",
+#   srcs = ["server_entry.c"],
+#   deps = ["//seobeo:seobeo_server"], 
+#   linkstatic = False,
+#   visibility = ["//visibility:public"],
+# )
+
+# py_binary(
+#   name = "python_server",
+#   srcs = ["python_server.py"],
+#   deps = [
+#     ":mrjunejune_server_lib",
+#     "@pip_deps//:cffi",
+#   ],
+#   data = [":mrjunejune_server_lib"],
+# )
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/README.md	Fri Jan 02 18:13:32 2026 -0800
@@ -0,0 +1,115 @@
+# MrJuneJune Integration Tests
+
+This directory contains comprehensive integration tests for all mrjunejune endpoints.
+
+## Test Structure
+
+### Test Files
+- `integration_test.c` - Main integration test suite
+- `create_snapshots.c` - Utility to generate/update snapshot files
+- `shiba.webp` - Test image for image-to-webp conversion
+- `test_avi.avi` - Test video for video-to-mp4 conversion
+
+### Snapshot Directory
+- `snapshots/` - Contains expected HTTP responses for GET endpoints
+
+## Endpoints Tested
+
+### GET Endpoints (200 OK with Snapshot Verification)
+- `/` - Home page
+- `/resume` - Resume page
+- `/tools` - Tools page
+- `/tools/markdown_to_html` - Markdown to HTML converter
+- `/tools/file_converter` - File converter tool
+
+### GET Endpoints (301 Redirects)
+- `/index.html` → `/`
+- `/resume/index.html` → `/resume`
+- `/tools/index.html` → `/tools`
+- `/tools/markdown_to_html/index.html` → `/tools/markdown_to_html`
+- `/tools/file_converter/index.html` → `/tools/file_converter`
+
+### GET Endpoints (404 Not Found)
+- `/nonexistent`
+- `/does/not/exist`
+- `/missing.html`
+
+### POST Endpoints
+- `/api/convert/image-to-webp` - Converts images to WebP format
+  - Tests file upload, conversion, and download
+  - Verifies Content-Type: image/webp
+- `/api/convert/video-to-mp4` - Converts videos to MP4 format
+  - Tests file upload, conversion, and download
+  - Verifies Content-Type: video/mp4
+
+### Download Endpoint
+- `/api/download/:filename` - Download converted files
+  - Tested automatically as part of POST conversion tests
+
+## Running Tests
+
+### First Time Setup - Create Snapshots
+Before running tests for the first time, generate snapshots:
+
+```bash
+bazel run //mrjunejune:create_snapshots
+```
+
+This will:
+1. Start the mrjunejune server
+2. Make HTTP requests to all GET endpoints
+3. Save responses to `snapshots/` directory
+4. Stop the server
+
+### Run Integration Tests
+```bash
+bazel test //mrjunejune:integration_test
+```
+
+This will:
+1. Start the mrjunejune server on port 6969
+2. Test all GET endpoints against their snapshots
+3. Test POST conversion endpoints with real file uploads
+4. Verify downloads work correctly
+5. Report pass/fail for each test
+
+### View Test Output
+```bash
+bazel test //mrjunejune:integration_test --test_output=all
+```
+
+## Test Coverage
+
+✓ All 10 registered endpoints are tested
+✓ Snapshot testing for HTML responses
+✓ File upload and conversion testing
+✓ Download functionality testing
+✓ Error handling (404 responses)
+✓ Redirect testing (301 responses)
+
+## Updating Tests
+
+### When HTML Changes
+If you modify any HTML templates:
+
+```bash
+# Regenerate snapshots
+bazel run //mrjunejune:create_snapshots
+
+# Run tests to verify
+bazel test //mrjunejune:integration_test
+```
+
+### When Adding New Endpoints
+1. Update `main.c` with new route
+2. Add test case to `integration_test.c`
+3. Add snapshot config to `create_snapshots.c` (for GET)
+4. Regenerate snapshots
+5. Run tests
+
+## Notes
+
+- Tests require FFmpeg to be installed for video/image conversion tests
+- Server runs on port 6969 during tests
+- Test files are cleaned up automatically after download
+- Converted files are stored in `/tmp/` during tests
--- a/mrjunejune/test/create_snapshots.c	Fri Jan 02 18:02:22 2026 -0800
+++ b/mrjunejune/test/create_snapshots.c	Fri Jan 02 18:13:32 2026 -0800
@@ -106,11 +106,23 @@
   // Define snapshots to create - paths that should succeed (200 OK)
   SnapshotConfig success_snapshots[] = {
     {"/", 200, snapshot_path, TEST_HOST, TEST_PORT},
-    {"/index.html", 200, snapshot_path, TEST_HOST, TEST_PORT},
+    {"/resume", 200, snapshot_path, TEST_HOST, TEST_PORT},
+    {"/tools", 200, snapshot_path, TEST_HOST, TEST_PORT},
+    {"/tools/markdown_to_html", 200, snapshot_path, TEST_HOST, TEST_PORT},
+    {"/tools/file_converter", 200, snapshot_path, TEST_HOST, TEST_PORT},
   };
   int num_success = sizeof(success_snapshots) / sizeof(success_snapshots[0]);
 
-  // Define snapshots for error paths (404)
+  // Define snapshots for redirect endpoints (301)
+  SnapshotConfig redirect_snapshots[] = {
+    {"/index.html", 301, snapshot_path, TEST_HOST, TEST_PORT},
+    {"/resume/index.html", 301, snapshot_path, TEST_HOST, TEST_PORT},
+    {"/tools/index.html", 301, snapshot_path, TEST_HOST, TEST_PORT},
+    {"/tools/markdown_to_html/index.html", 301, snapshot_path, TEST_HOST, TEST_PORT},
+    {"/tools/file_converter/index.html", 301, snapshot_path, TEST_HOST, TEST_PORT},
+  };
+  int num_redirects = sizeof(redirect_snapshots) / sizeof(redirect_snapshots[0]);
+
   SnapshotConfig error_snapshots[] = {
     {"/nonexistent", 404, snapshot_path, TEST_HOST, TEST_PORT},
     {"/does/not/exist", 404, snapshot_path, TEST_HOST, TEST_PORT},
@@ -135,8 +147,22 @@
     }
   }
 
+  // Create redirect snapshots
+  printf("\nCreating snapshots for redirect paths:\n\n");
+  for (int i = 0; i < num_redirects; i++)
+  {
+    if (Seobeo_Snapshot_Create(&redirect_snapshots[i]) == 0)
+    {
+      total_passed++;
+    }
+    else
+    {
+      total_failed++;
+    }
+  }
+
   // Create error snapshots
-  printf("Creating snapshots for error paths:\n\n");
+  printf("\nCreating snapshots for error paths:\n\n");
   for (int i = 0; i < num_errors; i++)
   {
     if (Seobeo_Snapshot_Create(&error_snapshots[i]) == 0)
--- a/mrjunejune/test/integration_test.c	Fri Jan 02 18:02:22 2026 -0800
+++ b/mrjunejune/test/integration_test.c	Fri Jan 02 18:13:32 2026 -0800
@@ -380,6 +380,229 @@
   return 0;
 }
 
+// Helper: Send POST request with file data
+int send_post_file(Seobeo_Handle *client, const char *path, const char *file_data, size_t file_size)
+{
+  char request_buffer[8192];
+  int header_len = snprintf(
+    request_buffer, sizeof(request_buffer),
+    "POST %s HTTP/1.1\r\n"
+    "Host: %s\r\n"
+    "Content-Type: application/octet-stream\r\n"
+    "Content-Length: %zu\r\n"
+    "Connection: close\r\n"
+    "\r\n",
+    path, TEST_HOST, file_size
+  );
+
+  if (header_len < 0 || header_len >= sizeof(request_buffer))
+  {
+    fprintf(stderr, "Request header too large\n");
+    return -1;
+  }
+
+  // Send headers
+  Seobeo_Handle_Queue(client, (uint8*)request_buffer, (uint32)header_len);
+
+  // Send file data in chunks if needed
+  size_t remaining = file_size;
+  const char *ptr = file_data;
+  while (remaining > 0)
+  {
+    size_t chunk_size = remaining > 4096 ? 4096 : remaining;
+    Seobeo_Handle_Queue(client, (uint8*)ptr, (uint32)chunk_size);
+    ptr += chunk_size;
+    remaining -= chunk_size;
+  }
+
+  return Seobeo_Handle_Flush(client);
+}
+
+// Helper: Extract JSON field value from response body
+char* extract_json_field(const char *json, const char *field, char *buffer, size_t buffer_size)
+{
+  char search_pattern[256];
+  snprintf(search_pattern, sizeof(search_pattern), "\"%s\":\"", field);
+
+  const char *start = strstr(json, search_pattern);
+  if (!start)
+  {
+    return NULL;
+  }
+
+  start += strlen(search_pattern);
+  const char *end = strchr(start, '"');
+  if (!end)
+  {
+    return NULL;
+  }
+
+  size_t len = end - start;
+  if (len >= buffer_size)
+  {
+    len = buffer_size - 1;
+  }
+
+  memcpy(buffer, start, len);
+  buffer[len] = '\0';
+
+  return buffer;
+}
+
+// Helper: Test POST file conversion
+int test_file_conversion(const char *endpoint, const char *test_file_path,
+                         const char *expected_format, pid_t server_pid)
+{
+  printf("  Testing: POST %s\n", endpoint);
+
+  // Read test file
+  size_t file_size;
+  char *file_data = read_file(test_file_path, &file_size);
+  if (!file_data)
+  {
+    printf("    ✗ Failed to read test file: %s\n", test_file_path);
+    return -1;
+  }
+
+  printf("    → Loaded test file (%zu bytes)\n", file_size);
+
+  // Create client and send request
+  Seobeo_Handle *client = create_test_client();
+  if (!client)
+  {
+    printf("    ✗ Failed to create client connection\n");
+    free(file_data);
+    return -1;
+  }
+
+  if (send_post_file(client, endpoint, file_data, file_size) < 0)
+  {
+    printf("    ✗ Failed to send POST request\n");
+    free(file_data);
+    Seobeo_Handle_Destroy(client);
+    return -1;
+  }
+
+  free(file_data);
+
+  // Read response
+  char *response = NULL;
+  size_t response_len = 0;
+  if (read_http_response(client, &response, &response_len) < 0)
+  {
+    printf("    ✗ Failed to read response\n");
+    Seobeo_Handle_Destroy(client);
+    return -1;
+  }
+
+  Seobeo_Handle_Destroy(client);
+
+  // Parse status
+  int status = parse_http_status(response);
+  if (status != 200)
+  {
+    printf("    ✗ Conversion failed with status: %d\n", status);
+    printf("    Response: %s\n", response);
+    free(response);
+    return -1;
+  }
+
+  printf("    ✓ Status code: 200\n");
+
+  // Extract download URL from JSON response
+  const char *body = strstr(response, "\r\n\r\n");
+  if (!body)
+  {
+    printf("    ✗ No response body found\n");
+    free(response);
+    return -1;
+  }
+  body += 4;
+
+  char download_url[512];
+  if (!extract_json_field(body, "download_url", download_url, sizeof(download_url)))
+  {
+    printf("    ✗ Failed to extract download_url from response\n");
+    printf("    Response body: %s\n", body);
+    free(response);
+    return -1;
+  }
+
+  printf("    ✓ Conversion succeeded\n");
+  printf("    ✓ Download URL: %s\n", download_url);
+  free(response);
+
+  // Test downloading the converted file
+  printf("    → Testing download: GET %s\n", download_url);
+
+  client = create_test_client();
+  if (!client)
+  {
+    printf("    ✗ Failed to create client for download\n");
+    return -1;
+  }
+
+  if (send_http_request(client, download_url, NULL) < 0)
+  {
+    printf("    ✗ Failed to send download request\n");
+    Seobeo_Handle_Destroy(client);
+    return -1;
+  }
+
+  response = NULL;
+  response_len = 0;
+  if (read_http_response(client, &response, &response_len) < 0)
+  {
+    printf("    ✗ Failed to read download response\n");
+    Seobeo_Handle_Destroy(client);
+    return -1;
+  }
+
+  Seobeo_Handle_Destroy(client);
+
+  status = parse_http_status(response);
+  if (status != 200)
+  {
+    printf("    ✗ Download failed with status: %d\n", status);
+    free(response);
+    return -1;
+  }
+
+  // Find body in download response
+  body = strstr(response, "\r\n\r\n");
+  if (!body)
+  {
+    printf("    ✗ No file data in download response\n");
+    free(response);
+    return -1;
+  }
+  body += 4;
+
+  size_t downloaded_size = response_len - (body - response);
+
+  // Verify content type in response headers
+  const char *content_type = strstr(response, "Content-Type: ");
+  if (!content_type)
+  {
+    printf("    ✗ No Content-Type header in download\n");
+    free(response);
+    return -1;
+  }
+
+  if (strstr(content_type, expected_format) == NULL)
+  {
+    printf("    ✗ Wrong content type (expected %s)\n", expected_format);
+    free(response);
+    return -1;
+  }
+
+  printf("    ✓ Downloaded converted file (%zu bytes)\n", downloaded_size);
+  printf("    ✓ Content-Type: %s\n", expected_format);
+
+  free(response);
+  return 0;
+}
+
 // Helper: Start test server
 pid_t start_test_server(const char *server_binary)
 {
@@ -498,10 +721,23 @@
   // Define test cases - paths that should succeed (200 OK)
   TestCase success_tests[] = {
     {"/", 200, NULL, NULL, NULL, 0},
-    {"/index.html", 200, NULL, NULL, NULL, 0},
+    {"/resume", 200, NULL, NULL, NULL, 0},
+    {"/tools", 200, NULL, NULL, NULL, 0},
+    {"/tools/markdown_to_html", 200, NULL, NULL, NULL, 0},
+    {"/tools/file_converter", 200, NULL, NULL, NULL, 0},
   };
   int num_success_tests = sizeof(success_tests) / sizeof(success_tests[0]);
 
+  // Define test cases - paths that should redirect (301)
+  TestCase redirect_tests[] = {
+    {"/index.html", 301, NULL, NULL, NULL, 0},
+    {"/resume/index.html", 301, NULL, NULL, NULL, 0},
+    {"/tools/index.html", 301, NULL, NULL, NULL, 0},
+    {"/tools/markdown_to_html/index.html", 301, NULL, NULL, NULL, 0},
+    {"/tools/file_converter/index.html", 301, NULL, NULL, NULL, 0},
+  };
+  int num_redirect_tests = sizeof(redirect_tests) / sizeof(redirect_tests[0]);
+
   // Define test cases - paths that should fail (404)
   TestCase failure_tests[] = {
     {"/nonexistent", 404, NULL, NULL, NULL, 0},
@@ -515,6 +751,10 @@
   {
     init_test_case(&success_tests[i]);
   }
+  for (int i = 0; i < num_redirect_tests; i++)
+  {
+    init_test_case(&redirect_tests[i]);
+  }
   for (int i = 0; i < num_failure_tests; i++)
   {
     init_test_case(&failure_tests[i]);
@@ -536,6 +776,22 @@
 
   printf("\n");
 
+  // Run redirect tests
+  printf("Running tests for paths that should redirect:\n");
+  for (int i = 0; i < num_redirect_tests; i++)
+  {
+    if (execute_test_case(&redirect_tests[i], server_pid) == 0)
+    {
+      passed_tests++;
+    }
+    else
+    {
+      failed_tests++;
+    }
+  }
+
+  printf("\n");
+
   // Run failure tests
   printf("Running tests for paths that should fail:\n");
   for (int i = 0; i < num_failure_tests; i++)
@@ -572,11 +828,48 @@
     failed_tests++;
   }
 
+  printf("\n");
+
+  // Test POST endpoints
+  printf("Running tests for POST conversion endpoints:\n");
+
+  // Test image-to-webp conversion
+  if (test_file_conversion("/api/convert/image-to-webp",
+                           "mrjunejune/test/shiba.webp",
+                           "image/webp",
+                           server_pid) == 0)
+  {
+    passed_tests++;
+  }
+  else
+  {
+    failed_tests++;
+  }
+
+  printf("\n");
+
+  // Test video-to-mp4 conversion
+  if (test_file_conversion("/api/convert/video-to-mp4",
+                           "mrjunejune/test/test_avi.avi",
+                           "video/mp4",
+                           server_pid) == 0)
+  {
+    passed_tests++;
+  }
+  else
+  {
+    failed_tests++;
+  }
+
   // Cleanup test cases
   for (int i = 0; i < num_success_tests; i++)
   {
     cleanup_test_case(&success_tests[i]);
   }
+  for (int i = 0; i < num_redirect_tests; i++)
+  {
+    cleanup_test_case(&redirect_tests[i]);
+  }
   for (int i = 0; i < num_failure_tests; i++)
   {
     cleanup_test_case(&failure_tests[i]);
Binary file mrjunejune/test/shiba.webp has changed
--- a/mrjunejune/test/snapshots/index.html.snapshot	Fri Jan 02 18:02:22 2026 -0800
+++ b/mrjunejune/test/snapshots/index.html.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -1,245 +1,202 @@
-HTTP/1.1 200 OK
-Content-Type: text/html; charset=utf-8
-Content-Length: 12120
+HTTP/1.1 301 Moved Permanently
+Content-Type: text/plain
+Content-Length: 0
 Connection: close
+Body: 
 
-<!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" />
+t/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <style>
+      .epi-photo {
+        display: flex;
+        justify-content: center;
+        margin-bottom: 10px;
+      }
+    </style>
   </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>
+     <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
 
-       <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">
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
 
-         <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>
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+     <main>
+       <p>Hi, my name is Juntae, but most people call me June or MrJuneJune.</p>
+
+       <p>I am a software engineer with experience spanning a wide range of companies, from small startups to FAANGs....</p>
+       <p>I know it is lame to work for them, but I have a dog so I need to put foods on my table.</p>
+
+       <div class="epi-photo">
+         <img id="currentPhoto" style="opacity: 0; transition: opacity 0.2s;" />
        </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>
+       <p>During my free time, I like to write codes mostly in C, Python, and Typescript. All in mono repo styles using mercurial and bazel. (I know that is mentally ill...)</p>
+       <p>Feel free to check it out. My bad code..</p>
 
-       <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>
+       <h2>Links</h2>
+       <ul>
+         <li><a href="https://zenbu.babocoder.com/file/tip">Repository</a> - Check out my monorepo code</li>
+         <li><a href="/resume">Resume</a> - My professional experiences </li>
+         <li><a href="/tools">Tools</a> - Tools </li>
+         <!-- <li><a href="/blogs">Blogs</a> - Personal Blogs where I rant </li> -->
+       </ul> 
+     </main>
+     <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
 
-       <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>
+  <script>
+    let arr = Array.from({ length: 18 }, (_, i) => i+1);
+    function setRandomImages() {
+      const randomIndex = Math.floor(Math.random() * arr.length);
+      const pos = arr[randomIndex];
+      currentPhoto.src = `/public/epi-photos/webp/${pos}.webp`;
+      currentPhoto.onload = () => {
+        currentPhoto.style.opacity = "1";
+      };
+      setTimeout(() => setRandomImages(), 1000);
+    }
+    setRandomImages();
+  </script>
+</htmlLocation: /
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/snapshots/resume.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -0,0 +1,401 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 15108
+Connection: close
+
+<!doctype html>
+<html lang="en">
+  <head>
+    <link rel="icon" type="image/svg+xml" href="/public/epi_all_colors.svg">
+
+<link rel="preload" href="/public/fonts/Roboto-Regular.ttf" as="font"  crossorigin>
+<link rel="preload" href="/public/fonts/Roboto-Thin.ttf"as="font" crossorigin>
+
+<link rel="preload" href="/public/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin>
+<link rel="preload" href="/public/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin>
+
+<link rel="preload" href="/public/fonts/more-sugar.extras.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <link rel="preload" href="resume.css" as="style" />
+    <link rel="stylesheet" href="resume.css" />
+  </head>
+  <body>
+    <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
+
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
+
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+    <main>
+      <div class="info">
+        <a href="/public/resume.pdf">Download PDF</a>
+        <hr>
+        <p><span class="header-firstname-style"> JUNTAE </span><span class="header-lastname-style">PARK</span><p>
+        <p class="header-position-style"> SOFTWARE ENGINEER </p>
+        <div class="header-address-style"> 
+          Bay Area, CA, USA
+        </div>
+        <div class="header-social-style">
+          <p> <a href="tel:+016505311728">(US) 650-531-1728</a> | <a href="tel:+014375808026">(CA) 437-580-8026</a> | <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 9 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. <br><br> 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>
+      <div id="footer"></div>
+    </main>
+    <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
+
+    <script href="index.js"></script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/snapshots/resume_index.html.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -0,0 +1,203 @@
+HTTP/1.1 301 Moved Permanently
+Content-Type: text/plain
+Content-Length: 0
+Connection: close
+Body: 
+
+t/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <style>
+      .epi-photo {
+        display: flex;
+        justify-content: center;
+        margin-bottom: 10px;
+      }
+    </style>
+  </head>
+  <body>
+     <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
+
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
+
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+     <main>
+       <p>Hi, my name is Juntae, but most people call me June or MrJuneJune.</p>
+
+       <p>I am a software engineer with experience spanning a wide range of companies, from small startups to FAANGs....</p>
+       <p>I know it is lame to work for them, but I have a dog so I need to put foods on my table.</p>
+
+       <div class="epi-photo">
+         <img id="currentPhoto" style="opacity: 0; transition: opacity 0.2s;" />
+       </div>
+
+       <p>During my free time, I like to write codes mostly in C, Python, and Typescript. All in mono repo styles using mercurial and bazel. (I know that is mentally ill...)</p>
+       <p>Feel free to check it out. My bad code..</p>
+
+       <h2>Links</h2>
+       <ul>
+         <li><a href="https://zenbu.babocoder.com/file/tip">Repository</a> - Check out my monorepo code</li>
+         <li><a href="/resume">Resume</a> - My professional experiences </li>
+         <li><a href="/tools">Tools</a> - Tools </li>
+         <!-- <li><a href="/blogs">Blogs</a> - Personal Blogs where I rant </li> -->
+       </ul> 
+     </main>
+     <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
+
+  </body>
+  <script>
+    let arr = Array.from({ length: 18 }, (_, i) => i+1);
+    function setRandomImages() {
+      const randomIndex = Math.floor(Math.random() * arr.length);
+      const pos = arr[randomIndex];
+      currentPhoto.src = `/public/epi-photos/webp/${pos}.webp`;
+      currentPhoto.onload = () => {
+        currentPhoto.style.opacity = "1";
+      };
+      setTimeout(() => setRandomImages(), 1000);
+    }
+    setRandomImages();
+  </script>
+</htmlLocation: /
+Location: /resume
+
--- a/mrjunejune/test/snapshots/root.snapshot	Fri Jan 02 18:02:22 2026 -0800
+++ b/mrjunejune/test/snapshots/root.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -1,245 +1,212 @@
 HTTP/1.1 200 OK
-Content-Type: text/html; charset=utf-8
-Content-Length: 12120
+Content-Type: text/html
+Content-Length: 5322
 Connection: close
 
 <!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" />
+    <title> MrJuneJune </title>
+    <link rel="icon" type="image/svg+xml" href="/public/epi_all_colors.svg">
+
+<link rel="preload" href="/public/fonts/Roboto-Regular.ttf" as="font"  crossorigin>
+<link rel="preload" href="/public/fonts/Roboto-Thin.ttf"as="font" crossorigin>
+
+<link rel="preload" href="/public/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin>
+<link rel="preload" href="/public/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin>
+
+<link rel="preload" href="/public/fonts/more-sugar.extras.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <style>
+      .epi-photo {
+        display: flex;
+        justify-content: center;
+        margin-bottom: 10px;
+      }
+    </style>
   </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>
+     <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
 
-       <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">
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
 
-         <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>
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+     <main>
+       <p>Hi, my name is Juntae, but most people call me June or MrJuneJune.</p>
+
+       <p>I am a software engineer with experience spanning a wide range of companies, from small startups to FAANGs....</p>
+       <p>I know it is lame to work for them, but I have a dog so I need to put foods on my table.</p>
+
+       <div class="epi-photo">
+         <img id="currentPhoto" style="opacity: 0; transition: opacity 0.2s;" />
        </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>
+       <p>During my free time, I like to write codes mostly in C, Python, and Typescript. All in mono repo styles using mercurial and bazel. (I know that is mentally ill...)</p>
+       <p>Feel free to check it out. My bad code..</p>
 
-       <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>
+       <h2>Links</h2>
+       <ul>
+         <li><a href="https://zenbu.babocoder.com/file/tip">Repository</a> - Check out my monorepo code</li>
+         <li><a href="/resume">Resume</a> - My professional experiences </li>
+         <li><a href="/tools">Tools</a> - Tools </li>
+         <!-- <li><a href="/blogs">Blogs</a> - Personal Blogs where I rant </li> -->
+       </ul> 
+     </main>
+     <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
 
-       <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>
+  <script>
+    let arr = Array.from({ length: 18 }, (_, i) => i+1);
+    function setRandomImages() {
+      const randomIndex = Math.floor(Math.random() * arr.length);
+      const pos = arr[randomIndex];
+      currentPhoto.src = `/public/epi-photos/webp/${pos}.webp`;
+      currentPhoto.onload = () => {
+        currentPhoto.style.opacity = "1";
+      };
+      setTimeout(() => setRandomImages(), 1000);
+    }
+    setRandomImages();
+  </script>
 </html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/snapshots/tools.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -0,0 +1,184 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 4152
+Connection: close
+
+<!doctype html>
+<html lang="en">
+  <head>
+    <link rel="icon" type="image/svg+xml" href="/public/epi_all_colors.svg">
+
+<link rel="preload" href="/public/fonts/Roboto-Regular.ttf" as="font"  crossorigin>
+<link rel="preload" href="/public/fonts/Roboto-Thin.ttf"as="font" crossorigin>
+
+<link rel="preload" href="/public/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin>
+<link rel="preload" href="/public/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin>
+
+<link rel="preload" href="/public/fonts/more-sugar.extras.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <link rel="stylesheet" href="/tools/index.css" />
+  </head>
+  <body>
+      <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
+
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
+
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+     <main>
+       <h1 class="title"> Tools </h1>
+       <ul class="nav-list">
+         <li><a href="/tools/markdown_to_html">MarkDown to HTML</a></li>
+         <li><a href="/tools/file_converter">Images to Webp / Video to Mp4</a></li>
+       </ul>
+       <h3> TODOs </h3>
+       <p> Probably should add this... </p>
+       <ul class="nav-list">
+         <li>- Simple online LaTex editor.</li>
+         <li>- Online HLS player.</li>
+       </ul>
+     </main>
+     <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
+
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/snapshots/tools_file_converter.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -0,0 +1,315 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 7742
+Connection: close
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>File Format Converter</title>
+    <link rel="icon" type="image/svg+xml" href="/public/epi_all_colors.svg">
+
+<link rel="preload" href="/public/fonts/Roboto-Regular.ttf" as="font"  crossorigin>
+<link rel="preload" href="/public/fonts/Roboto-Thin.ttf"as="font" crossorigin>
+
+<link rel="preload" href="/public/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin>
+<link rel="preload" href="/public/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin>
+
+<link rel="preload" href="/public/fonts/more-sugar.extras.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <style>
+        .container {
+            max-width: 800px;
+            margin: 2rem auto;
+            padding: 2rem;
+        }
+
+        .converter-section {
+            border-radius: 8px;
+            border: 2px solid var(--lightgray);
+            padding: 2rem;
+            margin-bottom: 2rem;
+        }
+
+        .converter-section h2 {
+            margin-top: 0;
+            color: var(--black);
+        }
+
+        .file-input-wrapper {
+            margin: 1rem 0;
+        }
+
+        .file-input-wrapper label {
+            display: block;
+            margin-bottom: 0.5rem;
+            font-weight: 600;
+        }
+
+        input[type="file"] {
+            width: 50%;
+            padding: 0.5rem;
+            border: 2px dashed #ccc;
+            border-radius: 4px;
+            background: white;
+        }
+
+        button {
+            background: var(--purple);
+            font-family: "More Thin", sans-serif;
+            color: var(--gray-gradient);
+            border: none;
+            padding: 0.75rem 1.5rem;
+            border-radius: 4px;
+            cursor: pointer;
+            font-size: 1rem;
+            margin-top: 1rem;
+        }
+
+        button:hover {
+            background: var(--orange);
+        }
+
+        button:disabled {
+            background: var(--gray);
+            cursor: not-allowed;
+        }
+
+        .result {
+            margin-top: 1rem;
+            padding: 1rem;
+            background: white;
+            border-radius: 4px;
+            display: none;
+        }
+
+        .result.show {
+            display: block;
+        }
+
+        .result.success {
+            border-left: 4px solid var(--blue);
+        }
+
+        .result.error {
+            border-left: 4px solid var(--red);
+        }
+
+        .download-link {
+            display: inline-block;
+            margin-top: 0.5rem;
+            color: var(--awesome);
+            text-decoration: none;
+        }
+
+        .download-link:hover {
+            text-decoration: underline;
+        }
+
+        .loading {
+            display: none;
+            margin-top: 1rem;
+        }
+
+        .loading.show {
+            display: block;
+        }
+    </style>
+</head>
+<body>
+    <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
+
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
+
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+
+    <div class="container">
+        <h1>File Format Converter</h1>
+        <p>Convert your images and videos to different formats using FFmpeg</p>
+
+        <div class="converter-section">
+            <h2>Image to WebP Converter</h2>
+            <p>Upload an image file (PNG, JPG, GIF, etc.) to convert it to WebP format</p>
+
+            <div class="file-input-wrapper">
+                <label for="imageInput">Choose an image file:</label>
+                <input type="file" id="imageInput" accept="image/*">
+            </div>
+
+            <button id="convertImageBtn" onclick="convertImageToWebP()">Convert to WebP</button>
+
+            <div class="loading" id="imageLoading">Converting... Please wait.</div>
+
+            <div class="result" id="imageResult">
+                <p id="imageMessage"></p>
+                <a id="imageDownload" class="download-link" style="display: none;">Download WebP Image</a>
+            </div>
+        </div>
+
+        <div class="converter-section">
+            <h2>Video to MP4 Converter</h2>
+            <p>Upload a video file (AVI, MOV, MKV, etc.) to convert it to MP4 format</p>
+
+            <div class="file-input-wrapper">
+                <label for="videoInput">Choose a video file:</label>
+                <input type="file" id="videoInput" accept="video/*">
+            </div>
+
+            <button id="convertVideoBtn" onclick="convertVideoToMP4()">Convert to MP4</button>
+
+            <div class="loading" id="videoLoading">Converting... Please wait.</div>
+
+            <div class="result" id="videoResult">
+                <p id="videoMessage"></p>
+                <a id="videoDownload" class="download-link" style="display: none;">Download MP4 Video</a>
+            </div>
+        </div>
+        <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
+
+    </div>
+    <script src="/tools/file_converter/index.js"></script>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/snapshots/tools_file_converter_index.html.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -0,0 +1,174 @@
+HTTP/1.1 301 Moved Permanently
+Content-Type: text/plain
+Content-Length: 0
+Connection: close
+Body: 
+
+reload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <link rel="stylesheet" href="/tools/index.css" />
+  </head>
+  <body>
+      <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
+
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
+
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+     <main>
+       <h1 class="title"> Tools </h1>
+       <ul class="nav-list">
+         <li><a href="/tools/markdown_to_html">MarkDown to HTML</a></li>
+         <li><a href="/tools/file_converter">Images to Webp / Video to Mp4</a></li>
+       </ul>
+       <h3> TODOs </h3>
+       <p> Probably should add this... </p>
+       <ul class="nav-list">
+         <li>- Simple online LaTex editor.</li>
+         <li>- Online HLS player.</li>
+       </ul>
+     </main>
+     <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
+
+  </body>
+</htmlLocation: /tools/file_converter
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/snapshots/tools_index.html.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -0,0 +1,468 @@
+HTTP/1.1 301 Moved Permanently
+Content-Type: text/plain
+Content-Length: 0
+Connection: close
+Body: 
+
+="font/woff" crossorigin>
+
+<link rel="preload" href="/public/fonts/more-sugar.extras.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <style>
+        .container {
+            max-width: 800px;
+            margin: 2rem auto;
+            padding: 2rem;
+        }
+
+        .converter-section {
+            border-radius: 8px;
+            border: 2px solid var(--lightgray);
+            padding: 2rem;
+            margin-bottom: 2rem;
+        }
+
+        .converter-section h2 {
+            margin-top: 0;
+            color: var(--black);
+        }
+
+        .file-input-wrapper {
+            margin: 1rem 0;
+        }
+
+        .file-input-wrapper label {
+            display: block;
+            margin-bottom: 0.5rem;
+            font-weight: 600;
+        }
+
+        input[type="file"] {
+            width: 50%;
+            padding: 0.5rem;
+            border: 2px dashed #ccc;
+            border-radius: 4px;
+            background: white;
+        }
+
+        button {
+            background: var(--purple);
+            font-family: "More Thin", sans-serif;
+            color: var(--gray-gradient);
+            border: none;
+            padding: 0.75rem 1.5rem;
+            border-radius: 4px;
+            cursor: pointer;
+            font-size: 1rem;
+            margin-top: 1rem;
+        }
+
+        button:hover {
+            background: var(--orange);
+        }
+
+        button:disabled {
+            background: var(--gray);
+            cursor: not-allowed;
+        }
+
+        .result {
+            margin-top: 1rem;
+            padding: 1rem;
+            background: white;
+            border-radius: 4px;
+            display: none;
+        }
+
+        .result.show {
+            display: block;
+        }
+
+        .result.success {
+            border-left: 4px solid var(--blue);
+        }
+
+        .result.error {
+            border-left: 4px solid var(--red);
+        }
+
+        .download-link {
+            display: inline-block;
+            margin-top: 0.5rem;
+            color: var(--awesome);
+            text-decoration: none;
+        }
+
+        .download-link:hover {
+            text-decoration: underline;
+        }
+
+        .loading {
+            display: none;
+            margin-top: 1rem;
+        }
+
+        .loading.show {
+            display: block;
+        }
+    </style>
+</head>
+<body>
+    <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
+
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
+
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+
+    <div class="container">
+        <h1>File Format Converter</h1>
+        <p>Convert your images and videos to different formats using FFmpeg</p>
+
+        <div class="converter-section">
+            <h2>Image to WebP Converter</h2>
+            <p>Upload an image file (PNG, JPG, GIF, etc.) to convert it to WebP format</p>
+
+            <div class="file-input-wrapper">
+                <label for="imageInput">Choose an image file:</label>
+                <input type="file" id="imageInput" accept="image/*">
+            </div>
+
+            <button id="convertImageBtn" onclick="convertImageToWebP()">Convert to WebP</button>
+
+            <div class="loading" id="imageLoading">Converting... Please wait.</div>
+
+            <div class="result" id="imageResult">
+                <p id="imageMessage"></p>
+                <a id="imageDownload" class="download-link" style="display: none;">Download WebP Image</a>
+            </div>
+        </div>
+
+        <div class="converter-section">
+            <h2>Video to MP4 Converter</h2>
+            <p>Upload a video file (AVI, MOV, MKV, etc.) to convert it to MP4 format</p>
+
+            <div class="file-input-wrapper">
+                <label for="videoInput">Choose a video file:</label>
+                <input type="file" id="videoInput" accept="video/*">
+            </div>
+
+            <button id="convertVideoBtn" onclick="convertVideoToMP4()">Convert to MP4</button>
+
+            <div class="loading" id="videoLoading">Converting... Please wait.</div>
+
+            <div class="result" id="videoResult">
+                <p id="videoMessage"></p>
+                <a id="videoDownload" class="download-link" style="display: none;">Download MP4 Video</a>
+            </div>
+        </div>
+        <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
+
+    </div>
+    <script src="/tools/file_converter/index.js"></script>
+</body>
+</htmlLocation: /tools
+
+ition-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>
+      <div id="footer"></div>
+    </main>
+    <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
+
+    <script href="index.js"></script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/snapshots/tools_markdown_to_html.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -0,0 +1,261 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 5891
+Connection: close
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Markdown to HTML Converter</title>
+    <link rel="icon" type="image/svg+xml" href="/public/epi_all_colors.svg">
+
+<link rel="preload" href="/public/fonts/Roboto-Regular.ttf" as="font"  crossorigin>
+<link rel="preload" href="/public/fonts/Roboto-Thin.ttf"as="font" crossorigin>
+
+<link rel="preload" href="/public/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin>
+<link rel="preload" href="/public/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin>
+
+<link rel="preload" href="/public/fonts/more-sugar.extras.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <link rel="stylesheet" href="markdown_to_html/index.css" />
+</head>
+<body>
+    <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
+
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
+
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+    <div class="header">
+        <h1>Markdown to HTML Converter</h1>
+    </div>
+    
+    <div class="container">
+        <div class="panel">
+            <div class="label">Markdown Input</div>
+            <textarea id="input" placeholder="Type your markdown here..."># Welcome to Markdown Converter
+
+## Features
+
+This converter supports:
+
+- **Bold text** and *italic text*
+- [Links](https://example.com)
+- `inline code`
+- ~~strikethrough~~
+
+### Lists
+
+1. Ordered lists
+2. Like this one
+3. With numbers
+
+- Unordered lists
+- Use dashes
+- Or asterisks
+
+### Code Blocks
+
+```
+function example() {
+    return "Hello World";
+}
+```
+
+### Blockquotes
+
+> This is a blockquote
+> It can span multiple lines
+
+---
+
+### Images
+
+![Alt text](https://via.placeholder.com/150)
+
+**Try editing this text!**</textarea>
+        </div>
+        
+        <div class="panel">
+            <div class="title">
+              <div class="label">HTML Output</div>
+              <button id="copy"> Copy </button>
+            </div>
+            <div id="output"></div>
+        </div>
+    </div>
+    <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
+
+    <script src="/markdown_to_html.js"></script>
+    <script>
+        function convert() {
+          output.innerHTML = '';
+          const markdown = input.value;
+          renderMarkdown(output, markdown);
+        }
+        input.addEventListener('input', convert);
+        
+        convert();
+
+        copy.addEventListener('click', () => {
+          const htmlBlob = new Blob([output.innerHTML], { type: 'text/html'});
+          const textBlob = new Blob([output.innerText], { type: 'text/plain'});
+          const data = [new ClipboardItem({
+            'text/html': htmlBlob,
+            'text/plain': textBlob
+          })];
+          navigator.clipboard.write(data).then(() => {
+            copy.textContent = "Copied!";
+            setTimeout(() => {
+              copy.textContent = "Copy";
+              copy.classList.remove('success');
+            }, 1000);
+          }).catch(err => {
+            console.error('Failed to copy: ', err);
+          });
+        });
+    </script>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/test/snapshots/tools_markdown_to_html_index.html.snapshot	Fri Jan 02 18:13:32 2026 -0800
@@ -0,0 +1,204 @@
+HTTP/1.1 301 Moved Permanently
+Content-Type: text/plain
+Content-Length: 0
+Connection: close
+Body: 
+
+t/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
+<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
+
+<link rel="preload" href="/base.css" as="style" />
+<link rel="stylesheet" href="/base.css" />
+
+
+    <style>
+      .epi-photo {
+        display: flex;
+        justify-content: center;
+        margin-bottom: 10px;
+      }
+    </style>
+  </head>
+  <body>
+     <style>
+  :root {
+    --header-background: var(--white);
+    --header-color: rgb(var(--black));
+    --link-hover-accent: var(--awesome);
+  }
+
+  /* Fixed icon in top left corner */
+  #themeToggle {
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    background: var(--header-background);
+    display: flex;
+    align-items: center;
+    border-radius: 50%;
+    cursor: pointer;
+    z-index: 1000;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transition: transform 0.2s ease;
+  }
+
+  #themeToggle:hover {
+    transform: scale(1.05);
+  }
+
+  /* Professional header */
+  header {
+    margin: auto;
+    padding: 1.5em 1em;
+    font-family: "More", sans-serif;
+    box-shadow: 0 2px 8px rgba(var(--black), 5%);
+    width: 720px;
+    max-width: calc(100% - 2em);
+    text-align: center;
+  }
+
+  header h1 {
+    margin: 0;
+    font-size: 1.8em;
+    font-weight: 700;
+    letter-spacing: -0.5px;
+  }
+
+  header h1 a {
+    text-decoration: none;
+    color: var(--header-color);
+  }
+
+  header h1 a::before {
+    display: none;
+  }
+
+  /* Mobile responsiveness */
+  @media (max-width: 720px) {
+    #themeToggle {
+      top: 15px;
+      left: 15px;
+    }
+
+    header {
+      padding: 1em;
+    }
+
+    header h1 {
+      font-size: 1.5em;
+    }
+  }
+
+  @media (max-width: 480px) {
+    #themeToggle {
+      top: 10px;
+      left: 10px;
+    }
+
+    #themeToggle img {
+      height: 40px;
+      width: 40px;
+    }
+
+    header h1 {
+      font-size: 1.3em;
+    }
+  }
+
+  #logo {
+    width: 300px;
+  }
+
+  /* 1. DEFINE THE DEFAULTS (Light Mode) */
+  :root {
+    --logo-invert: invert(0);
+    --epi-grayscale: grayscale(0) brightness(1);
+  }
+  
+  /* 2. MANUAL DARK OVERRIDE */
+  html.dark {
+    --logo-invert: invert(1);
+    --epi-grayscale: grayscale(1);
+  }
+  
+  /* 3. MANUAL LIGHT OVERRIDE */
+  html.light-mode {
+    --logo-invert: invert(0);
+    --epi-grayscale: brightness(2.9) grayscale(1);
+  }
+  
+  /* 4. SYSTEM PREFERENCE */
+  @media (prefers-color-scheme: dark) {
+    :root:not(.light-mode) {
+      --logo-invert: invert(1);
+    }
+  }
+  
+  /* 5. APPLY TO ELEMENTS */
+  #logo {
+    -webkit-filter: var(--logo-invert);
+    filter: var(--logo-invert);
+    transition: filter 0.3s ease;
+  }
+  
+  .epi-logo {
+    -webkit-filter: var(--epi-grayscale);
+    filter: var(--epi-grayscale);
+    transition: filter 0.3s ease;
+  }
+</style>
+
+<div id="themeToggle">
+  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
+</div>
+
+<header>
+  <h1><a href="/">MrJuneJune</a></h1>
+</header>
+<script src="/index.js"></script>
+
+
+     <main>
+       <p>Hi, my name is Juntae, but most people call me June or MrJuneJune.</p>
+
+       <p>I am a software engineer with experience spanning a wide range of companies, from small startups to FAANGs....</p>
+       <p>I know it is lame to work for them, but I have a dog so I need to put foods on my table.</p>
+
+       <div class="epi-photo">
+         <img id="currentPhoto" style="opacity: 0; transition: opacity 0.2s;" />
+       </div>
+
+       <p>During my free time, I like to write codes mostly in C, Python, and Typescript. All in mono repo styles using mercurial and bazel. (I know that is mentally ill...)</p>
+       <p>Feel free to check it out. My bad code..</p>
+
+       <h2>Links</h2>
+       <ul>
+         <li><a href="https://zenbu.babocoder.com/file/tip">Repository</a> - Check out my monorepo code</li>
+         <li><a href="/resume">Resume</a> - My professional experiences </li>
+         <li><a href="/tools">Tools</a> - Tools </li>
+         <!-- <li><a href="/blogs">Blogs</a> - Personal Blogs where I rant </li> -->
+       </ul> 
+     </main>
+     <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
+  <small>&copy; 2026 June Park</small>
+</div>
+
+  </body>
+  <script>
+    let arr = Array.from({ length: 18 }, (_, i) => i+1);
+    function setRandomImages() {
+      const randomIndex = Math.floor(Math.random() * arr.length);
+      const pos = arr[randomIndex];
+      currentPhoto.src = `/public/epi-photos/webp/${pos}.webp`;
+      currentPhoto.onload = () => {
+        currentPhoto.style.opacity = "1";
+      };
+      setTimeout(() => setRandomImages(), 1000);
+    }
+    setRandomImages();
+  </script>
+</htmlLocation: /
+Location: /resume
+Location: /tools/markdown_to_html
+
Binary file mrjunejune/test/test_avi.avi has changed