diff --git a/.cspell/words.txt b/.cspell/words.txt
new file mode 100644
index 0000000..6f78e49
--- /dev/null
+++ b/.cspell/words.txt
@@ -0,0 +1,100 @@
+# Project dictionary for content/**/*.md (names, tools, jargon)
+Andwati
+angr
+archlinux
+Ashish
+bashfu
+binarysith
+binwalk
+bmod
+bruteforcing
+chall
+ciphertexts
+cmark
+comming
+disassemblers
+diskchal
+distros
+dlresolve
+dnsmasq
+dokploy
+Einherjar
+exiftool
+expecially
+Fastbin
+Garuda
+Geospatial
+Ghidra
+Gitaly
+Gitea
+Hashnode
+Heartbleed
+Heredocs
+homoglyphs
+honggfuzz
+hotspot
+Hotspots
+IDOR
+jadx
+Kernighan
+keyserver
+Kleppmann
+libc
+malloc
+MINECRAFTISFUN
+mmuctf
+mockingspectre
+MVCC
+Namecheap
+Niki
+Noam
+openpgp
+Parmar
+Pgadget
+Pipx
+Pwntools
+RDBMS
+RDBMSs
+Revealme
+Riccomini
+Ritchie
+Sandboxing
+seccomp
+Shazeer
+shellcode
+Shellshock
+Sidekiq
+Sigreturn
+SIGSEGV
+SNMP
+SROP
+staticnoise
+stego
+strikethrough
+subresource
+Sussman
+syscalls
+Tcache
+tera
+tshark
+unbootable
+Userland
+Vaswani
+vuejs
+Wireshark
+
+# Review: possible typos or intentional wordplay in existing posts (kept so checks pass)
+Ledilect
+Metawork
+iddleness
+thatsss
+trol
+whyyy
+
+# Intentional homoglyph text in the mmuctf2025 writeup
+cοmfort
+doоrs
+this
+соrner
+girl
+Jobless
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..4e839fa
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,12 @@
+node_modules
+.next
+.git
+.gitignore
+.env*
+!.env.example
+Dockerfile
+.dockerignore
+README.md
+npm-debug.log*
+*.md
+!content/**/*.md
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100755
index 0000000..5ee7abd
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1 @@
+pnpm exec lint-staged
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..5cffb2c
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,4 @@
+# Prettier only formats writing/pages. Biome owns code, CSS and JSON.
+*
+!content/
+!content/**
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..4130777
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,5 @@
+{
+ "proseWrap": "preserve",
+ "embeddedLanguageFormatting": "off",
+ "overrides": [{ "files": "*.md", "options": { "printWidth": 100 } }]
+}
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..8e8a230
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,7 @@
+{
+ "recommendations": [
+ "biomejs.biome",
+ "esbenp.prettier-vscode",
+ "streetsidesoftware.code-spell-checker"
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..8a063a3
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,12 @@
+{
+ "editor.formatOnSave": true,
+ "editor.defaultFormatter": "biomejs.biome",
+ "[markdown]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.wordWrap": "on"
+ },
+ "prettier.enable": true,
+ "cSpell.language": "en",
+ "cSpell.enabledFileTypes": { "markdown": true },
+ "editor.codeActionsOnSave": { "source.fixAll.biome": "explicit" }
+}
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..4fb4882
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,37 @@
+# syntax=docker/dockerfile:1
+
+# ---- deps: install with a cached pnpm store ----
+FROM node:24-alpine AS deps
+ENV PNPM_HOME=/pnpm PATH=/pnpm:$PATH
+RUN corepack enable
+WORKDIR /app
+COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
+RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
+ pnpm install --frozen-lockfile
+
+# ---- build ----
+FROM node:24-alpine AS build
+ENV PNPM_HOME=/pnpm PATH=/pnpm:$PATH NEXT_TELEMETRY_DISABLED=1
+RUN corepack enable
+WORKDIR /app
+COPY --from=deps /app/node_modules ./node_modules
+COPY . .
+# Umami is read at build time (pages are prerendered), so pass these as build args.
+ARG PUBLIC_UMAMI_SCRIPT_URL
+ARG PUBLIC_UMAMI_WEBSITE_ID
+ENV PUBLIC_UMAMI_SCRIPT_URL=$PUBLIC_UMAMI_SCRIPT_URL \
+ PUBLIC_UMAMI_WEBSITE_ID=$PUBLIC_UMAMI_WEBSITE_ID
+RUN pnpm build
+
+# ---- runtime: standalone server only ----
+FROM node:24-alpine AS runner
+ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 PORT=3000 HOSTNAME=0.0.0.0
+# Only `node` is needed at runtime; drop npm/yarn/corepack.
+RUN rm -rf /usr/local/lib/node_modules /usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/corepack /opt/yarn-*
+WORKDIR /app
+COPY --from=build --chown=node:node /app/.next/standalone ./
+COPY --from=build --chown=node:node /app/.next/static ./.next/static
+COPY --from=build --chown=node:node /app/public ./public
+USER node
+EXPOSE 3000
+CMD ["node", "server.js"]
diff --git a/content/about.md b/content/about.md
new file mode 100644
index 0000000..f1a2fad
--- /dev/null
+++ b/content/about.md
@@ -0,0 +1,33 @@
+---
+title: "About"
+---
+
+# Ian Andwati
+
+## Some things about me:
+
+- I'm a software engineer by day. Cyber Security is my hobby and my side work.
+- I have a degree in computer science, and most of what I do for fun still centres on it.
+- I'm the captain of the [**binarysith**](https://ctftime.org/team/379200) CTF team. I play CTFs on the weekends under the alias **mockingspectre**.
+- I like infrastructure-level software: the code that other code runs on.
+- I write essays on software development, from personal experience to opinion pieces (with varying degrees of "success"). The blog has been going since 2021 and has moved around a lot: different domains, Medium, dev.to, Hashnode. This site is where I keep the originals.
+
+## Some things I'm interested in:
+
+- The intersection of software engineering and cyber security.
+- Low-level programming, because it's where performance and security meet.
+- Distributed systems and performance at scale.
+- Compiler design.
+- Database internals.
+- Reading, fiction and non-fiction alike, especially the classics.
+- Art, history and science.
+
+Check out my [reading](/reading), [writing](/writing) and [portfolio](/portfolio).
+
+### PGP
+
+For anything sensitive, you can reach me encrypted.
+
+- Fingerprint: `AD58 AAB7 A20D 8523 CBF5 9A79 1F20 FED0 AA05 B0DA`
+- Public key: [/.well-known/pgp-key.txt](/.well-known/pgp-key.txt)
+- Also on: [keys.openpgp.org](https://keys.openpgp.org/search?q=AD58AAB7A20D8523CBF59A791F20FED0AA05B0DA) and [keyserver.ubuntu.com](https://keyserver.ubuntu.com/pks/lookup?op=vindex&search=0xAD58AAB7A20D8523CBF59A791F20FED0AA05B0DA)
diff --git a/content/portfolio/example-project.md b/content/portfolio/example-project.md
new file mode 100644
index 0000000..6a78b99
--- /dev/null
+++ b/content/portfolio/example-project.md
@@ -0,0 +1,11 @@
+---
+title: "Example Project"
+description: "Placeholder portfolio entry establishing the schema."
+role: "Author"
+dateStart: "2026-01-01"
+outcome: "Established the portfolio content schema."
+links:
+ - label: "Source"
+ url: "https://github.com/andwati"
+tags: ["placeholder"]
+---
diff --git a/content/reading/attention-is-all-you-need.md b/content/reading/attention-is-all-you-need.md
new file mode 100644
index 0000000..48a6332
--- /dev/null
+++ b/content/reading/attention-is-all-you-need.md
@@ -0,0 +1,11 @@
+---
+title: "Attention Is All You Need"
+kind: "paper"
+authors: ["Ashish Vaswani", "Noam Shazeer", "Niki Parmar"]
+url: "https://arxiv.org/abs/1706.03762"
+coverImage: "/covers/attention-is-all-you-need.jpg"
+rating: 5
+status: "read"
+dateFinished: "2026-02-03"
+tags: ["machine-learning", "papers"]
+---
diff --git a/content/reading/designing-data-intensive-applications-2nd-edition.md b/content/reading/designing-data-intensive-applications-2nd-edition.md
new file mode 100644
index 0000000..07d1f33
--- /dev/null
+++ b/content/reading/designing-data-intensive-applications-2nd-edition.md
@@ -0,0 +1,10 @@
+---
+title: "Designing Data-Intensive Applications, 2nd Edition"
+kind: "book"
+authors: ["Martin Kleppmann", "Chris Riccomini"]
+url: "https://www.oreilly.com/library/view/designing-data-intensive-applications/9781098119058/"
+coverImage: "/covers/designing-data-intensive-applications-2nd-edition.webp"
+rating: 5
+status: "reading"
+tags: ["distributed-systems"]
+---
diff --git a/content/reading/structure-and-interpretation-of-computer-programs.md b/content/reading/structure-and-interpretation-of-computer-programs.md
new file mode 100644
index 0000000..d8e20fe
--- /dev/null
+++ b/content/reading/structure-and-interpretation-of-computer-programs.md
@@ -0,0 +1,10 @@
+---
+title: "Structure and Interpretation of Computer Programs"
+kind: "book"
+authors: ["Harold Abelson", "Gerald Jay Sussman"]
+coverImage: "/covers/structure-and-interpretation-of-computer-programs.jpg"
+rating: 5
+status: "read"
+dateFinished: "2026-01-20"
+tags: ["computer-science", "programming"]
+---
diff --git a/content/writing/a-fresh-coat-of-paint.md b/content/writing/a-fresh-coat-of-paint.md
new file mode 100644
index 0000000..da0de73
--- /dev/null
+++ b/content/writing/a-fresh-coat-of-paint.md
@@ -0,0 +1,55 @@
+---
+title: "A Fresh Coat Of Paint"
+description: "Migrating to Zola"
+date: "2023-08-24"
+tags: ["zola", "blog", "tera", "rust"]
+---
+
+Using Zola as my preferred static site generator
+
+After using Hugo for over eight months I got tired of it and looked for other alternatives. That's when I stumbled upon Zola. Zola is a static site generator (SSG), similar to [Hugo](https://gohugo.io/), [Pelican](https://blog.getpelican.com/), and [Jekyll](https://jekyllrb.com/).
+
+It is written in Rust and uses the Tera template engine, similar to Jinja2, Django templates, Liquid, and Twig. SSGs use dynamic templates to transform content into static HTML pages. Static sites are thus very fast and require no databases, making them easy to host.
+
+My previous Hugo site used a theme because I wasn't really ready to learn Go's template engine. I'm already familiar with Python Django and its template system so using Tera wasn't hard because it's similar to jinja2 and the Django template syntax.
+
+Content is written in [CommonMark](https://commonmark.org/), a strongly defined, highly compatible specification of [Markdown](https://www.markdownguide.org/). Zola uses [pulldown-cmark](https://github.com/raphlinus/pulldown-cmark#pulldown-cmark) to parse markdown files. The goal of this library is 100% compliance with the CommonMark spec. It adds a few additional features such as parsing footnotes, Github-flavored tables, Github-flavored task lists, and strikethrough.
+
+Zola comes with built-in syntax highlighting, but you must first enable it in the configuration file.
+
+Zola is very minimalistic, it is installed only as a single binary, with no extra dependencies needed. It is configured in `toml` and you only use what is needed. For example here is the configuration for this site `config.toml`:
+
+```toml
+title = "Ian Andwati"
+description = "Ian Andwati's personal website"
+base_url = "https://andwati.github.io"
+
+generate_categories_pages = false
+generate_tags_pages = false
+generate_feed = true
+feed_filename = "rss.xml"
+minify_html = false
+taxonomies = [{ name = 'tags', feed = false }]
+compile_sass = true
+
+[markdown]
+highlight_code = true
+highlight_theme = "gruvbox-dark"
+
+[link_checker]
+
+[extra]
+author = "Ian Andwati"
+```
+
+## Inspiration
+
+The motivation to use Zola also came from my decision to move from independently developed themes. I decided to write the HTML and CSS myself and endeavor to maintain the site individually. The base CSS is borrowed from [Reilly Tucker Siemens](https://tuckersiemens.com/) who had created a nice gruvbox palette for his site.
+
+I improved on it by adding an archive page, pagination, a comment system, and Google Analytics (more of these in later posts). I also implemented article read time and word count.
+
+## What next
+
+The site is a work in progress and is far from polished. I plan on implementing a newsletter to notify readers of new posts. The site is primarily a dark theme, in the future I'll also add theme toggling and maybe different palettes.
+
+You can subscribe to the site's RSS feed at [https://andwati.com/rss.xml](https://andwati.com/rss.xml).
diff --git a/content/writing/from-c-to-machine-code.md b/content/writing/from-c-to-machine-code.md
new file mode 100644
index 0000000..7535a15
--- /dev/null
+++ b/content/writing/from-c-to-machine-code.md
@@ -0,0 +1,322 @@
+---
+title: "From C to Machine Code: What Actually Runs"
+description: "Before diving into how to break a program, we need to understand what the computer is actually executing"
+date: "2026-04-08"
+tags: ["assembly", "rev", "pwn"]
+---
+
+
+
+Before diving into how to break a program, we need to understand what the computer is actually executing. When you write a C program, the processor doesn't understand a single line of it. The C language exists for _our_ benefit, allowing us to write logic without having to manually shuffle bits around in the processor.
+
+To bridge this gap, we use a compiler (like `GCC`), which translates our human-readable C code into machine code—raw binary instructions. Assembly language is simply the human-readable representation of that machine code.
+
+Because we usually don't have the original C source code when analyzing malware or playing a CTF, we are forced to read the assembly. (Though tools like Ghidra can try to decompile assembly back into C-like pseudocode to save us from staring at assembly instructions all day).
+
+Let's look at what a basic `printf("Hello World!");` program actually turns into.
+
+```c
+#include
+
+int main(){
+ printf("hello world\n");
+ return 0;
+}
+```
+
+We will compile the hello world C program, then dump the assembly in Intel syntax(it defaults to AT&T syntax, a cancer).
+
+```sh
+gcc -o hello hello.c && objdump -d -M intel hello | grep -A 15 "**:**"
+```
+
+
+
+```asm
+0000000000001139 :
+ 1139: 55 push rbp
+ 113a: 48 89 e5 mov rbp,rsp
+ 113d: 48 8d 05 c0 0e 00 00 lea rax,[rip+0xec0] # 2004 <_IO_stdin_used+0x4>
+ 1144: 48 89 c7 mov rdi,rax
+ 1147: e8 e4 fe ff ff call 1030
+ 114c: b8 00 00 00 00 mov eax,0x0
+ 1151: 5d pop rbp
+ 1152: c3 ret
+
+Disassembly of section .fini:
+
+0000000000001154 <_fini>:
+ 1154: 48 83 ec 08 sub rsp,0x8
+ 1158: 48 83 c4 08 add rsp,0x8
+ 115c: c3 ret
+
+```
+
+Notice how different this looks from C. The processor executes different instruction sets depending on its architecture. The two most common architectures you will encounter are 32-bit (x86) and 64-bit (x86_64 or just x64/AMD64/Intel 64).
+
+## **The Processor's Workbench: Registers**
+
+To process data rapidly, the CPU doesn't want to constantly reach all the way out to your system's RAM. Instead, it uses registers—extremely fast, temporary storage buckets located directly on the processor.
+
+Here are the critical x64 registers you need to know:
+
+- **`rip` (Instruction Pointer):** The most important register for exploitation. It points to the exact memory address of the _next_ instruction the CPU is supposed to execute.
+- **`rsp` (Stack Pointer):** Points to the very top of your current stack frame.
+- **`rbp` (Base Pointer):** Points to the bottom of your current stack frame.
+
+### **General Purpose Registers & Calling Conventions**
+
+There are also general-purpose registers (`rax`, `rbx`, `rcx`, `rdx`, `rsi`, `rdi`, and `r8` through `r15`). While they can be used for general math and data storage, they have strict roles when functions are called.
+
+In x64 Linux, when a function is called, the arguments are passed directly into registers in this specific order:
+
+1. `rdi` (First argument)
+2. `rsi` (Second argument)
+3. `rdx` (Third argument)
+4. `rcx` (Fourth argument)
+5. `r8` (Fifth argument)
+6. `r9` (Sixth argument)
+
+
+
+### **Register Sizes and "Words"**
+
+Registers have different sizes depending on the architecture, and you can reference smaller chunks of a larger register. In binary exploitation, you'll frequently see data referred to by size:
+
+**Word:** 2 bytes
+
+**Dword (Double Word):** 4 bytes
+
+**Qword (Quad Word):** 8 bytes
+
+Here is how x64 registers break down into smaller accessible chunks:
+
+| 8-Byte (Qword)[64 bit] | Lower 4-Bytes (Dword)[lower 32 bits] | Lower 2-Bytes (Word)[lower 16 bits] | Lower 1-Byte[lower 8 bits] |
+| :--------------------- | :----------------------------------- | :---------------------------------- | :------------------------- |
+| rax | eax | ax | al |
+| rbx | ebx | bx | bl |
+| rcx | ecx | cx | cl |
+| rdx | edx | dx | dl |
+| rdi | edi | di | dil |
+| rsi | edi | si | sil |
+| rsp | esp | sp | spl |
+| rbp | ebp | bp | bpl |
+| rip | eip | - | - |
+| r8 | r8d | r8w | r8b |
+| r9 | r9d | r9w | r9b |
+| r10 | r10d | r10w | r10b |
+| r11 | r11d | r11w | r11b |
+| r12 | r12d | r12w | r12b |
+| r13 | r13d | r13w | r13b |
+| r14 | r14d | r14w | r14b |
+| r15 | r15d | r15w | r15b |
+
+
+
If you are dealing with a 32-bit (x86) binary, the 8-byte 'R' registers don't exist. The largest buckets you have are the 4-byte 'E' registers (`eax`, `ebp`, etc.).
+
+## **The Stack**
+
+The stack is a segment of memory heavily used during execution. It's primarily used to store local variables, keep track of function calls, and manage control flow. It operates as a LIFO (Last-In, First-Out) structure—meaning you can only add (push) to the top of it, and remove (pop) from the top of it.
+
+The boundaries of the current stack space are tracked by `rbp` (the base) and `rsp` (the top). When you declare a local variable in C, like `int x = 5;`, the program allocates space for it on the stack.
+
+Consider stack.c
+
+```c
+
+#include
+
+int main() {
+
+ int x = 5;
+
+ puts("hi");
+
+}
+
+```
+
+Compile this with the command:
+
+```sh
+gcc -o stack stack.c && objdump -d -M intel stack | grep -A 15 ":"
+```
+
+```asm
+0000000000001139 :
+
+ 1139: 55 push rbp
+
+ 113a: 48 89 e5 mov rbp,rsp
+
+ 113d: 48 83 ec 10 sub rsp,0x10
+
+ 1141: c7 45 fc 05 00 00 00 mov DWORD PTR [rbp-0x4],0x5
+
+ 1148: 48 8d 05 b5 0e 00 00 lea rax,[rip+0xeb5] # 2004 <_IO_stdin_used+0x4>
+
+ 114f: 48 89 c7 mov rdi,rax
+
+ 1152: e8 d9 fe ff ff call 1030
+
+ 1157: b8 00 00 00 00 mov eax,0x0
+
+ 115c: c9 leave
+
+ 115d: c3 ret
+
+Disassembly of section .fini:
+
+0000000000001160 <_fini>:
+
+ 1160: 48 83 ec 08 sub rsp,0x8
+
+```
+
+
+
+In your output, you'll see an instruction moving the value `0x5` into a memory location relative to the base pointer, usually something like `[rbp-0x4]`. That is your local variable resting on the stack.
+
+## **The Heap**
+
+We will just do an overview of this section. It can get quite complex very fast. We will eventually cover them in future articles.
+
+If the stack is the CPU’s fast, tightly organized workbench, the heap is the massive, slightly chaotic warehouse out back.
+
+The stack is great for small, temporary variables, but it has severe limitations: it is relatively small, and you must know exactly how much space you need at compile time. What if you want to load a 10MB image file? Or what if you are accepting user input and you don't know if the user will type 10 characters or 10,000?
+
+For dynamic, large, or unpredictable data, we use the **Heap**.
+
+Unlike the stack, which the CPU manages automatically by just moving the `rsp` register up and down, the heap is entirely manual. The programmer must explicitly ask the operating system for a chunk of memory, and more importantly, they must explicitly give it back when they are done.
+
+In C, this is done using the `malloc()` (memory allocate) and `free()` functions.
+
+Consider heap.c
+
+```c
+#include
+#include
+
+int main() {
+ // Ask the warehouse for 64 bytes of space
+ char *buffer = (char *)malloc(64);
+
+ // Put some data into that space
+ strcpy(buffer, "hello heap");
+
+ // Give the space back to the warehouse
+ free(buffer);
+
+ return 0;
+}
+
+```
+
+Now we do the necessary:
+
+```sh
+gcc -o heap heap.c && objdump -d -M intel heap | grep -A 20 ":"
+
+```
+
+
+
+```asm
+0000000000001149 **:**
+ 1149: 55 push rbp
+ 114a: 48 89 e5 mov rbp,rsp
+ 114d: 48 83 ec 10 sub rsp,0x10
+ 1151: bf 40 00 00 00 mov edi,0x40
+ 1156: e8 e5 fe ff ff call 1040
+ 115b: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
+ 115f: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
+ 1163: 48 ba 68 65 6c 6c 6f movabs rdx,0x6568206f6c6c6568
+ 116a: 20 68 65
+ 116d: 48 89 10 mov QWORD PTR [rax],rdx
+ 1170: c7 40 07 65 61 70 00 mov DWORD PTR [rax+0x7],0x706165
+ 1177: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
+ 117b: 48 89 c7 mov rdi,rax
+ 117e: e8 ad fe ff ff call 1030
+ 1183: b8 00 00 00 00 mov eax,0x0
+ 1188: c9 leave
+ 1189: c3 ret
+
+Disassembly of section .fini:
+```
+
+When you look at this assembly, you won't see data simply being pushed onto the stack. Instead, you will see instructions setting up arguments (like putting `0x40`—which is 64 in hex—into the `edi` register) followed by a `call` to `malloc@plt`.
+
+`malloc` acts as the warehouse manager. It goes out, finds 64 bytes of free space in the heap memory region, and returns a pointer (a memory address) to that space in the `tax` register.
+
+This manual management is exactly why the heap is such a prime target for exploitation. If a programmer calls `malloc` but forgets to call `free`, the program leaks memory. If they call `free` but keep using the pointer anyway, you get a "Use-After-Free" vulnerability. If they ask for 64 bytes but copy 100 bytes into it, you get a Heap Overflow. Breaking the heap means tricking the warehouse manager (`glibc`'s allocator) into giving you access to things you shouldn't have.
+
+## **The CPU's Instruction Set**
+
+Assembly might look like gibberish at first, but it essentially boils down to moving data, doing basic math, and jumping around memory. Here are the most common instructions you will encounter:
+
+### **Moving Data**
+
+- **`mov dest, src`**: Copies data from the source to the destination. (`mov rax, rdx` copies the value in `rdx` into `rax`).
+- **Dereferencing `[]`**: Brackets act like pointers in C. `mov rax, [rdx]` doesn't move `rdx` itself; it goes to the memory address stored in `rdx` and grabs the value sitting there. Conversely, `mov [rax], rdx` takes the value in `rdx` and writes it into the memory address pointed to by `rax`.
+- **`lea dest, src`**: Load Effective Address. It calculates a memory address and stores the _address itself_ in the destination, rather than the data at that address. (`lea rdi, [rbx+0x10]`).
+
+### **Math and Logic**
+
+- **`add dest, src` / `sub dest, src`**: Adds or subtracts the source from the destination, storing the result in the destination.
+- **`xor dest, src`**: Performs a bitwise exclusive OR. (You will frequently see `xor rax, rax`—this is simply an optimized way to set `rax` to 0).
+
+### **Stack Operations**
+
+- **`push reg`**: Subtracts from `rsp` to grow the stack, then places the register's value onto the new top of the stack.
+- **`pop reg`**: Takes the value from the top of the stack, puts it into the register, and adds to `rsp` to shrink the stack.
+
+### **Control Flow**
+
+- **`jmp address`**: Unconditionally redirects code execution to a new memory address.
+- **`call address`**: Used to invoke functions. It pushes the current `rip` onto the stack (so the program remembers where it was) and then jumps to the new address.
+- **`ret`**: Pops the saved address off the stack and places it back into `rip`, seamlessly resuming execution where it left off before the `call`.
+
+### **Conditionals and Flags**
+
+The CPU has a special register dedicated to **Flags**—individual bits that indicate the state of the processor (e.g., the Zero Flag, Carry Flag, Sign Flag).
+
+- **`cmp arg1, arg2`**: Compares two values by silently subtracting them. It doesn't save the mathematical result; instead, it updates the CPU Flags (like setting the Zero Flag if the two values were equal).
+- **`jz` / `jnz`**: Jump if Zero / Jump if Not Zero. These look at the CPU flags set by a previous `cmp` instruction. If the Zero Flag is set, `jz` will take the jump. If not, the program just continues to the next instruction.
+
+There is one register that contains flags. A flag is a particular bit of this register. If it is set or not, will typically mean something. Here is the list of flags.
+
+```txt
+00: Carry Flag
+01: always 1
+02: Parity Flag
+03: always 0
+04: Adjust Flag
+05: always 0
+06: Zero Flag
+07: Sign Flag
+08: Trap Flag
+09: Interruption Flag
+10: Direction Flag
+11: Overflow Flag
+12: I/O Privilege Field lower bit
+13: I/O Privilege Field higher bit
+14: Nested Task Flag
+15: Resume Flag
+```
+
+
+
+There are other flags then the one listed, however we really don't deal with them too much (and out of these, there are only a few we actively deal with).
+
+This has been a lot to unpack but it will get simpler with time. Now that we understand how C code becomes assembly, how the CPU juggles data in registers, and how the stack manages memory, we need to look at how all of this is packaged together by the operating system. Next, we will dive deeper into the structure of the ELF binary itself.
+
+You can support my work at [https://buymeacoffee.com/mockingspectre](https://buymeacoffee.com/mockingspectre)
+
+## Further Reading
+
+[https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture](https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture)
+[https://en.wikipedia.org/wiki/Assembly_language](https://en.wikipedia.org/wiki/Assembly_language)
diff --git a/content/writing/generate-django-secret-key.md b/content/writing/generate-django-secret-key.md
new file mode 100644
index 0000000..06a70fa
--- /dev/null
+++ b/content/writing/generate-django-secret-key.md
@@ -0,0 +1,37 @@
+---
+title: "Django Secret Key Tutorial"
+description: "Managing secrets"
+date: "2022-11-11"
+tags: ["tutorial", "django", "python", ".env"]
+---
+
+Managing the Django SECRET_KEY variable.
+
+The Django `SECRET_KEY` variable is very crucial to your Django application. The secret key must be a large random value and it must be kept secret. Leaking this value to unauthorized people could lead to a security breach. The SECRET_KEY is used in Django for cryptographic signing. It is used to generate tokens and hashes, they can be recreated using this variable. If it is not configured Django throws a `django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty` error
+
+# Using Environment Variables
+
+The secret key should not be committed to version control. It is best practice to store the value in a .env file which is added to the .gitignore file to un-track its changes. The values can be loaded programmatically into your settings.py file.
+
+# Generating A New Secret Key
+
+This solution is using python's secrets lib on the back
+
+```python
+from django.core.management.utils import get_random_secret_key
+# print new random secret key
+print(get_random_secret_key())
+```
+
+This code can be run in the terminal as a command:
+
+```python
+python -c 'from django.core.management.utils import get_random_secret_key; \
+ print(get_random_secret_key())'
+```
+
+Alternatively, If you are using python 3.6+ then you can use the `secrets.token_hex(\[nbytes=None])` function:
+
+```python
+python3 -c 'import secrets; print(secrets.token_hex(100))'
+```
diff --git a/content/writing/hello-world.md b/content/writing/hello-world.md
new file mode 100644
index 0000000..3cdaf7c
--- /dev/null
+++ b/content/writing/hello-world.md
@@ -0,0 +1,32 @@
+---
+title: "Hello World"
+description: "Hello world"
+date: "2022-11-04"
+tags: ["hugo", "blog", "go"]
+---
+
+How it begins
+
+In this post-web2.0 age, people seem to blog less and less, and blogs seem to be dying slowly. People are separated in different Apps where the content is not searchable by search engines.
+
+However, I still prefer to write using a blog.
+
+# Why this?
+
+The best way to learn something is to teach others the knowledge that you have gained. Regurgitating that information will solidify it more firmly in your mind.
+
+# What I write?
+
+Mostly random stuff and a few tutorials. I'll see where this goes.Although some of the blog posts may only be helpful to myself, but who knows, I hope they will be helpful to someone else in some day.
+
+# Static blog generator
+
+I use hugo as a static site generator.After trying a couple of blogging platforms and trying to build a few from scratch I decided to
+throw in the towel and opt in for a ready made solution, no need reinventing the wheel.
+
+Hugo is one of the most popular open-source static site generators. With its amazing speed and flexibility, Hugo makes building websites fun again.Hugo provides a robust theming system that is easy to implement but capable of producing even the most complicated websites.Hugo's Go-based templates provide just the right amount of logic to build anything from the simple to complex. For this site I decided to go with the [even theme](https://github.com/olOwOlo/hugo-theme-even). The commenting system is implemented using [Utterances](https://utteranc.es/)
+
+# Blog site hosting
+
+The site is hosted on github pages as evident by the \*.github.io domain name.I prefer this mainly because it is free and I don't have
+to switch to a different hosting provider.
diff --git a/content/writing/inertia.md b/content/writing/inertia.md
new file mode 100644
index 0000000..06440c6
--- /dev/null
+++ b/content/writing/inertia.md
@@ -0,0 +1,18 @@
+---
+title: "cognitive inertia"
+description: "inertia"
+date: "2025-02-26"
+tags: ["cognition"]
+---
+
+Staring at the void
+
+Cognitive inertia is the reason changing our habits can be difficult. If you want to overcome inertia you have to apply a force. I consider myself an eternal student, who is ready to learn anything, or so I thought. It happened but I had not noticed, I had stopped moving forward.
+
+## Metawork
+
+I will define this as the things we do before getting the "real" work doe. Its things like choosing the best IDE or text editor, setting up your coding environment, choosing the best note taking app, or even the 'best' operating system. They are the prerequisites of the actual work.
+
+I had been stuck on this loop, always trying to craft the perfect workflow. Setting up the best personalized linux distro, switching note taking apps, trying out multiple layouts, stylings and technologies for my blog, the list is endless.
+
+All of these metawork took more time thn the actual work; building, active learning and writing. Im going to stop all of these and start doing the important stuff.
diff --git a/content/writing/install-postgresql-15-on-arch-manjaro-garuda-linux.md b/content/writing/install-postgresql-15-on-arch-manjaro-garuda-linux.md
new file mode 100644
index 0000000..5ad1312
--- /dev/null
+++ b/content/writing/install-postgresql-15-on-arch-manjaro-garuda-linux.md
@@ -0,0 +1,170 @@
+---
+title: "Install PostgreSQL on Arch | Manjaro | Garuda Linux"
+description: "Getting PostgreSQL up and running on Arch Linux-based distros"
+date: "2023-02-16"
+tags: ["postgresql", "archlinux", "manjaro", "garuda", "linux"]
+---
+
+# Overview
+
+**PostgreSQL** is a powerful open-source relational database management system (RDBMS) that allows you to store and manage large amounts of data. It was first released in 1996 and has become one of the most popular RDBMSs in the world.
+
+PostgreSQL is designed to handle high levels of **concurrency**, providing features such as **MVCC (multi-version concurrency control)** that allow multiple users to access the same data simultaneously without conflicts. It is also **highly extensible**, with a large number of third-party extensions and libraries available that can be used to add functionality to the core database.
+
+Some of the key features of PostgreSQL include support for **complex SQL queries**, **advanced indexing** and **query optimization**, **transactional integrity**, and support for a **wide range of programming languages** and development frameworks.PostgreSQL is used by a wide range of organizations, from small businesses to large enterprises, and is particularly popular in industries such as finance, healthcare, and e-commerce, where high levels of data security and reliability are critical.
+
+In this tutorial, we’ll look at how to install PostgreSQL on Arch Linux, Manjaro, Garuda Linux, or any other Arch-based distro out there.
+
+# PostgreSQL use cases
+
+- **E-commerce websites:** PostgreSQL is a popular choice for e-commerce websites because it can handle large amounts of data and supports complex queries. It is used for product catalogs, order management, customer data, and more.
+- **Financial institutions:** PostgreSQL is used in financial institutions to store and manage transactional data, such as stock trades, bank transfers, and credit card transactions. It is highly secure and provides features such as transactional integrity and data encryption.
+- **Healthcare industry:** PostgreSQL is used in the healthcare industry to store patient data, such as medical records and diagnostic test results. It is also used for research purposes, where large amounts of data need to be stored and analyzed.
+- **Government agencies:** PostgreSQL is used by government agencies for a variety of purposes, including managing large datasets, storing and analyzing census data, and managing public health information.
+- **Mobile and web applications:** PostgreSQL is often used as a back-end database for mobile and web applications. It provides reliable data storage and retrieval and supports a wide range of programming languages and development frameworks.
+- **Geospatial applications:** PostgreSQL has built-in support for geospatial data and is often used for applications that require location-based data, such as mapping and GPS tracking.
+
+# Why PostgreSQL?
+
+Postgres offers a lot of advantages that make it an excellent choice for highly transactional environments regardless of application size and data volume. Its rich feature set and flexibility make it a popular choice for a wide range of applications and industries. Some of the top features are:
+
+- **ACID Compliance:** PostgreSQL is ACID (Atomicity, Consistency, Isolation, Durability) compliant, which means it provides high reliability, consistency, and data integrity, even in the presence of hardware failures, power outages, and other system errors.
+- **Extensibility:** PostgreSQL is highly extensible, allowing developers to add new data types, operators, and functions using its extension framework. This makes it easy to customize PostgreSQL to meet the specific needs of your application.
+- **Concurrency:** PostgreSQL provides a high level of concurrency, allowing multiple users to access the same data at the same time without conflicts. It uses a Multi-Version Concurrency Control (MVCC) model that enables fast and reliable access to data, even under heavy load.
+- **Full-text search:** PostgreSQL provides a powerful full-text search engine that supports advanced search capabilities, such as stemming, ranking, and relevance matching.
+- **Advanced indexing:** PostgreSQL provides a wide range of indexing options, including B-tree, Hash, GiST, SP-GiST, GIN, and BRIN. These indexing options allow developers to optimize database performance for their specific use cases.
+- **JSON support:** PostgreSQL provides native support for storing and querying JSON data, making it easy to work with modern web and mobile applications that rely on JSON for data exchange.
+- **Security:** PostgreSQL provides a high level of security, with features such as SSL support, client authentication, and role-based access control. It also provides encryption for both data at rest and data in transit.
+- **Scalability:** PostgreSQL is designed to scale horizontally and vertically, allowing you to add more nodes to a cluster or increase the resources of a single node to handle more load.
+
+# Install PostgreSQL on Arch | Manjaro | Garuda Linux
+
+Now with all that fluff out of the way, let's get to business. The steps have been tested on Arch Linux with the KDE desktop.
+
+> **Note:** Commands that should be run as the _postgres_ user are prefixed by `[postgres]$` in this article.
+
+## Step 1: Installing the PostgreSQL Package
+
+```sh
+sudo pacman -Syu postgresql
+```
+
+This command will update the package database and update all packages on the system then install the PostgreSQL package from your distribution mirrors. Never install a package without updating the system first. On a rolling release, this can lead to an unbootable system. Installing the package will also create a system user called _postgres_. You can now switch to the _postgres_ user using a privilege elevation program.
+
+You can switch to the PostgreSQL user by executing the following command:
+
+- If you have sudo and are in sudoers
+
+ ```sh
+ sudo -iu postgres
+ ```
+
+- Otherwise using su:
+
+ ```sh
+ su
+ su -l postgres
+ ```
+
+## Step 2: Initial Configuration
+
+Before PostgreSQL can function correctly, the database cluster must be initialized.
+
+### 2.1 We can confirm the installed PostgreSQL version by running
+
+```sh
+postgres --version ─╯
+postgres (PostgreSQL) 15.1
+```
+
+### 2.2 Set applicable entries in **/etc/locale.gen**
+
+```sh
+echo "en_US.UTF-8 UTF-8" | sudo tee /etc/locale.gen
+```
+
+### 2.3 Then run **\*\*locale-gen\*\*** to generate locale settings
+
+```sh
+sudo locale-gen
+Generating locales...
+ en_US.UTF-8... done
+Generation complete.
+```
+
+### 2.4 Initialize Postgres Data Directory
+
+You must first log in as the **postgres** user using the following command before you can initialize PostgreSQL’s data directory:
+
+```sh
+sudo su - postgres
+```
+
+### 2.5 With the following command, you can now initialize PostgreSQL’s data directory
+
+```sh
+[postgres]$ initdb -D /var/lib/postgres/data
+```
+
+### Step 3: PostgreSQL Service Management
+
+### 3.1 Check PostgreSQL status with the following command
+
+```sh
+systemctl status postgresql ─╯
+ postgresql.service - PostgreSQL database server
+ Loaded: loaded (/usr/lib/systemd/system/postgresql.service; disabled; preset: disabled)
+ Active: inactive (dead)
+```
+
+### 3.2 Start the PostgreSQL service by running the following command
+
+```sh
+sudo systemctl start postgresql
+```
+
+### 3.3 Enable the PostgreSQL service to start automatically at boot by running the following command
+
+```sh
+sudo systemctl enable postgresql
+```
+
+### 3.4 Verify that PostgreSQL is running by running the following command
+
+```sh
+sudo systemctl status postgresql ─╯
+● postgresql.service - PostgreSQL database server
+ Loaded: loaded (/usr/lib/systemd/system/postgresql.service; enabled; preset: disabled)
+ Active: active (running) since Thu 2023-02-16 22:52:43 EAT; 20s ago
+ Main PID: 26106 (postgres)
+ Tasks: 6 (limit: 8790)
+ Memory: 16.9M
+ CPU: 113ms
+ CGroup: /system.slice/postgresql.service
+ ├─26106 /usr/bin/postgres -D /var/lib/postgres/data
+ ├─26107 "postgres: checkpointer "
+ ├─26108 "postgres: background writer "
+ ├─26110 "postgres: walwriter "
+ ├─26111 "postgres: autovacuum launcher "
+ └─26112 "postgres: logical replication launcher "
+```
+
+### Change postgres user password
+
+To change the postgres user password execute the following command:
+
+```sh
+sudo -u postgres psql -c "ALTER USER postgres PASSWORD '$PGPASSWORD';"
+```
+
+# Resources
+
+- [Arch Linux Wiki](https://wiki.archlinux.org/title/PostgreSQL)
+- [Wikipedia](https://en.wikipedia.org/wiki/PostgreSQL)
+- [PostgreSQL Documentation](https://www.postgresql.org/docs/)
+
+# Conclusion
+
+Installing PostgreSQL on Arch Linux-based distribution is a straightforward process that can be completed in just a few steps. By following the steps outlined above, you can install, configure, and start the PostgreSQL database server on your Arch Linux system. Once installed, you can use PostgreSQL to store, manage, and query data for a wide range of applications and use cases. With its advanced features and high level of extensibility, PostgreSQL is a popular choice for developers and businesses seeking a robust and reliable database management system.
+
+You can connect to the PostgreSQL server using the psql command-line client or a graphical tool such as pgAdmin.
diff --git a/content/writing/integrating-netlify.md b/content/writing/integrating-netlify.md
new file mode 100644
index 0000000..6d13864
--- /dev/null
+++ b/content/writing/integrating-netlify.md
@@ -0,0 +1,150 @@
+---
+title: "Integrating Netlify CMS"
+description: "Integrating netlify cms"
+date: "2022-11-24"
+tags: ["blog", "hugo", "netlify", "netlify-cms", "github"]
+---
+
+Migrating to a better content management system through Netlify CMS
+
+# Heavy Lifting
+
+I use [Visual Studio Code](https://code.visualstudio.com/) to manually edit the blog post content on this website. This is quite a hassle because I have to deal with
+markdown files. There are many problems with this approach and several gotchas. I have to work on a local site repository to be able to edit the content. My GitHub credentials are also required to push my local changes to my remote repository on GitHub so that it can trigger the build process and publish the site.
+
+This process has helped me a lot to master markdown syntax and some practice on my git skills. It’s fun to update the website content following these steps but sometimes it can be frustrating. At those times, I really miss the user interface of content management systems. After careful consideration, I moved on with Netlify CMS. At its core, Netlify CMS is an open-source React app that acts as a wrapper for the Git workflow, using the GitHub, GitLab, or Bitbucket API. This provides many advantages, including:
+
+- **Fast, web-based UI:** With rich-text editing, real-time preview, and drag-and-drop media uploads.
+- **Platform agnostic:** Works with most static site generators.
+- **Easy installation:** Add two files to your site and hook up the backend by including those files in your build process or linking to our Content Delivery Network (CDN).
+- **Modern authentication:** Using GitHub, GitLab, or Bitbucket and JSON web tokens.
+- **Flexible content types:** Specify an unlimited number of content types with custom fields.
+- **Fully extensible:** Create custom-styled previews, UI widgets, and editor plugins.
+
+# Redeploying to Netlify
+
+I decided to move the site from GitHub pages to Netlify hosting to take full control of the platform. Hugo sites on Netlify can benefit from automatic framework detection and control over Hugo version selection. When you link a repository for a project, Netlify tries to detect the framework your site is using. If your site is built with Hugo, Netlify provides a suggested build command and publish directory: Hugo and public. The build process is straight forward but you can add custom options to your `netlify.toml` file, here are my options:
+
+```toml
+[build]
+command = "hugo"
+publish = "public"
+
+[build.environment]
+HUGO_VERSION = "0.105.0"
+```
+
+# Setting up Netlify CMS
+
+You can adapt Netlify CMS to a wide variety of projects. It works with any content written in markdown, JSON, YAML, or TOML files, stored in a repo on GitHub, GitLab, or Bitbucket. You can Netlify CMS to a site that's built with a common static site generator, like Jekyll, Hugo, Hexo, or Gatsby. The official documentation for installing on your website can be found at the [official site](https://www.netlifycms.org/docs/intro/)
+
+## Steps
+
+**Step 1**
+
+Create a static admin folder containing all Netlify CMS files, stored at the root of your published site. Where you store this folder in the source files depends on your static site generator. For Hugo, it is the `static` folder.
+
+`/static/admin`
+
+**Step 2**
+
+Inside the admin folder, create two files: `index.html` and `config.yml`. The first file `admin/index.html` is an entry point to Netlify CMS. You will access the CMS interface from `yourwebsite.com/admin` when everything is ready.
+
+**Step 3**
+
+The first file, `admin/index.html`, is the entry point for the Netlify CMS admin interface. Paste this code in index.html and save. This HTML starter page will load the Netlify CMS Javascript file:
+
+```html
+
+
+
+
+
+ Content Manager
+
+
+
+
+
+
+```
+
+**Step 4**
+
+Now let’s move to the configuration section. These are the configurations that go into the `config.yml` file. This process is different for every site. I followed the guidelines on the website and made minor adjustments. It worked on my website. The configuration options are available at the [docs](). This is how I configured my config.yml file:
+
+```yaml
+backend:
+ name: git-gateway
+ branch: netlify-cms # Branch to update (optional; defaults to master)
+
+# This line should *not* be indented
+publish_mode: editorial_workflow
+
+media_folder: 'static/images/uploads' # Media files will be stored in the repo under static/images/uploads
+public_folder: '/images/uploads' # The src attribute for uploaded media will begin with /images/uploads
+
+collections:
+ - name: 'post' # Used in routes, e.g., /admin/collections/blog
+ label: 'posts' # Used in the UI
+ folder: 'content/post' # The path to the folder where the documents are stored
+ create: true # Allow users to create new documents in this collection
+ slug: '{{year}}-{{month}}-{{day}}-{{slug}}' # Filename template, e.g., YYYY-MM-DD-title.md
+ fields: # The fields for each document, usually in front matter
+ - { label: 'Layout', name: 'layout', widget: 'hidden', default: 'blog' }
+ - { label: 'Title', name: 'title', widget: 'string' }
+ - { label: 'Draft', name: 'draft', widget: 'boolean', default: true }
+ - { label: 'Publish Date', name: 'date', widget: 'datetime' }
+ - { label: 'Last Modified', name: 'lastmod', widget: 'datetime' }
+ - { label: 'Body', name: 'body', widget: 'markdown' }
+ - { label: 'Keywords', name: 'keywords', widget: 'list' }
+ - { label: 'Tags', name: 'tags', widget: 'list' }
+ - { label: 'Categories', name: 'categories', widget: 'list' }
+ - { label: 'Comments', name: 'comment', widget: 'boolean', default: true }
+ - { label: 'Table of Contents', name: 'toc', widget: 'boolean', default: true }
+```
+
+**Step 5**
+
+**Authentication**
+
+Now that the Netlify CMS files are in place and configured, all that's left is to enable authentication.
+Netlify offers a built-in authentication service called Identity. In order to use it, connect your site repo with Netlify. Netlify has published a general [Step-by-Step Guide](https://www.netlify.com/blog/2016/10/27/a-step-by-step-guide-deploying-a-static-site-or-single-page-app/) for this, along with detailed guides for many popular static site generators
+
+Let’s first enable Netlify Identity and Git Gateway:
+
+- On your Netlify account, go to **Settings > Identity** and select **Enable Identity Service**
+- Under **Registration preferences**, select **Invite Only**.
+- If you want to enable login from external providers such as Google and GitHub, check the boxes you want to use, under **External Providers** section. I find it practical to log in with GitHub, so I added it.
+- Go to **Services > Git Gateway**, and click **Enable Git Gateway**. This authenticates with your Git Host and generates and API token.
+- Everything is almost set up. What we need now is a front-end interface to connect. We will add the following script in two places, to include the **Netlify Identity Widget** on our website:
+
+```html
+
+```
+
+We will use Netlify's [script injection](https://docs.netlify.com/site-deploys/post-processing/snippet-injection/) feature to add the script to our site. To use snippet injection, go to **Site Settings > Build & Deploy > Post processing**. Find the Snippet Injection section and select **Add Snippet**. Write a name for the script in the first box (e.g. Netlify Identity Widget). Paste the script inside the second box. Choose Insert before the `` tag of our website’s main index page. This script allows the user to redirect back to the `/admin/` path after completing the login with the Netlify Identity Widget:
+
+```html
+
+```
+
+**Step 5**
+
+Now we’re all set. Since we set our registration preferences to **“Invite Only”**, we need to invite ourselves as site users. To do this, select the Identity tab from the Netlify site dashboard and select the Invite Users button. Add your email address and send an invitation. You will receive an email. In your email, click **“accept the invitation”**. You will be directed to your website admin sign-up panel. Choose a password. Now you are ready to log in to Netlify CMS.
+
+# Setting up a custom domain
+
+I bought a custom domain from [Namecheap](https://namecheap.com), they provide some pretty good deals. After pointing the nameservers for the domain to the Netlify nameservers, voila! everything worked smoothly. For HTTPS support, Netlify enables automatic TLS certificates with Let’s Encrypt.
diff --git a/content/writing/javascript-exporting-modules.md b/content/writing/javascript-exporting-modules.md
new file mode 100644
index 0000000..81c5250
--- /dev/null
+++ b/content/writing/javascript-exporting-modules.md
@@ -0,0 +1,194 @@
+---
+title: "Export default and module.exports in Javascript"
+description: "Modules are the building blocks of modern JavaScript applications, allowing for the encapsulation of code into reusable components. Two primary systems govern the exportation of these modules: export default in ES6 and module.exports in CommonJS. "
+date: "2024-01-17"
+tags: ["javascript", "node"]
+---
+
+Modules are the building blocks of modern JavaScript applications, allowing for the encapsulation of code into reusable components. Two primary systems govern the exportation of these modules: export default in ES6 and module.exports in CommonJS.
+
+Javascript is a popular programming language that can run both in the browser and on the server. However, different environments may have different ways of organizing and importing Javascript modules. In this article, we will compare two common methods of exporting and importing modules: **export default** and **module.exports**.
+
+## What are modules?
+
+Modules are reusable pieces of code that can be separated into different files. Modules can export values, functions, classes, or objects that can be imported by other modules. This way, modules can avoid polluting the global scope and enable code reuse and modularity.
+
+## How to export modules in Node.js?
+
+Node.js is a runtime environment that allows Javascript to run on the server. Node.js uses a module system called CommonJS, which is based on the require and module.exports syntax.
+
+To export a module in Node.js, you can assign the value that you want to export to the module.exports object. For example:
+
+```javascript
+// my-module.js
+// export a function
+module.exports = function add(a, b) {
+ return a + b;
+};
+
+// export an object
+module.exports = {
+ name: 'Alice',
+ age: 25,
+};
+```
+
+To import a module in Node.js, you can use the require function and pass the path of the module file as an argument. The require function will return the value of module.exports from the module file. For example:
+
+```javascript
+// main.js
+// import a function
+const add = require('./my-module.js');
+console.log(add(2, 3)); // 5
+
+// import an object
+const person = require('./my-module.js');
+console.log(person.name); // Alice
+console.log(person.age); // 25
+```
+
+Note that Node.js will cache the modules that are imported with require, so if you import the same module multiple times, you will get the same instance of the module.
+
+## How to export modules in ES6?
+
+ES6 is the version of Javascript that introduced many new features, including a native module system. ES6 modules use the `import` and `export` syntax.
+
+To export a module in ES6, you can use the `export` keyword followed by the declaration of the value that you want to export. You can also use the export keyword with curly braces to export a list of named values. For example:
+
+```javascript
+// my-module.js
+// export a function
+export function add(a, b) {
+ return a + b;
+}
+
+// export a class
+export class Person {
+ constructor(name, age) {
+ this.name = name;
+ this.age = age;
+ }
+}
+
+// export an object
+export const person = {
+ name: 'Alice',
+ age: 25,
+};
+```
+
+To import a module in ES6, you can use the `import` keyword followed by the name of the value that you want to import and the path of the module file. You can also use the import keyword with curly braces to import a list of named values. For example:
+
+```javascript
+// main.js
+// import a function
+import { add } from './my-module.js';
+console.log(add(2, 3)); // 5
+
+// import a class
+import { Person } from './my-module.js';
+const person = new Person('Bob', 30);
+console.log(person.name); // Bob
+console.log(person.age); // 30
+
+// import an object
+import { person as Alice } from './my-module.js';
+console.log(Alice.name); // Alice
+console.log(Alice.age); // 25
+```
+
+Note that ES6 modules are imported and executed only once, so if you import the same module multiple times, you will get the same instance of the module.
+
+## What is the difference between export default and module.exports?
+
+One of the main differences between export default and module.exports is that export default is an ES6 feature, while module.exports is a CommonJS feature. Therefore, they are not compatible with each other by default. However, some tools like Babel or Webpack can transpile ES6 modules to CommonJS modules, or vice versa, to make them work together.
+
+Another difference is that export default can only export one value per module, while module.exports can export any value, including multiple values. For example:
+
+```javascript
+// my-module.js
+// export default a function
+export default function add(a, b) {
+ return a + b;
+}
+
+// export default an object
+export default {
+ name: "Alice",
+ age: 25,
+};
+
+// export default a class
+export default class Person {
+ constructor(name, age) {
+ this.name = name;
+ this.age = age;
+ }
+}
+```
+
+```javascript
+// my-module.js
+// export a function
+module.exports = function add(a, b) {
+ return a + b;
+};
+
+// export an object
+module.exports = {
+ name: 'Alice',
+ age: 25,
+};
+
+// export a class
+module.exports = class Person {
+ constructor(name, age) {
+ this.name = name;
+ this.age = age;
+ }
+};
+```
+
+Note that you can only have one export default statement per module, but you can have multiple module.exports statements. However, each module.exports statement will overwrite the previous one, so only the last one will be exported.
+
+To import a default export, you can use the import keyword without curly braces and assign any name to the imported value. For example:
+
+```javascript
+// main.js
+// import a default export
+import add from './my-module.js';
+console.log(add(2, 3)); // 5
+
+// import another default export
+import person from './my-module.js';
+console.log(person.name); // Alice
+console.log(person.age); // 25
+
+// import another default export
+import Person from './my-module.js';
+const person = new Person('Bob', 30);
+console.log(person.name); // Bob
+console.log(person.age); // 30
+```
+
+To import a module.exports value, you can use the require function and assign any name to the imported value. For example:
+
+```javascript
+// main.js
+// import a module.exports value
+const add = require('./my-module.js');
+console.log(add(2, 3)); // 5
+
+// import another module.exports value
+const person = require('./my-module.js');
+console.log(person.name); // Alice
+console.log(person.age); // 25
+
+// import another module.exports value
+const Person = require('./my-module.js');
+const person = new Person('Bob', 30);
+console.log(person.name); // Bob
+console.log(person.age); // 30
+```
+
+Node’s JavaScript has diverged from that of the browser. Understanding both CommonJS modules and ES6 modules is your first step in becoming a 10X developer. Happy coding!
diff --git a/content/writing/mmuctf2025.md b/content/writing/mmuctf2025.md
new file mode 100644
index 0000000..450932a
--- /dev/null
+++ b/content/writing/mmuctf2025.md
@@ -0,0 +1,407 @@
+---
+title: "mmuctf 2025 writeup"
+description: "mmuctf 2025 challenges writeup"
+date: "2025-08-03"
+tags: ["ctf", "rev", "web", "forensics"]
+---
+
+Over the weekend, I had the opportunity to participate in the mmuctf 2025. It was an individual jeopardy style CTF targeted towards beginners and intermediate people in cybersecurity. This is a write-up to explore some challenges I did, or at least almost did.
+
+## Welcome
+
+> Through the shadows of the cave, at the door I had a zeal to get a welcome flag, but I couldn't see it though
+> I could hear it calling for me to get it. Happy hacking
+> {: .prompt-info }
+
+This was a sanity check flag. I believe competitions pose such challenges that you can't get zero points. It's the same as flags in Discord servers, a flag after completing the feedback form, or just other free points.
+
+The challenge description talked about the `door`, my first instinct was to view the source of the front page. I got this html comment with what looked liked a base64 encoded string ``
+
+```zsh
+┌──(mockingspectre㉿blackout)-[~/ctf/mmuctf2025]
+└─$ echo -n "bW11Y3Rme3dlbGNvbWVfZmxhZ19hZGlvc19NdWNoQGNob30=" | base64 -d
+mmuctf{welcome_flag_adios_Much@cho}
+```
+
+## My First App
+
+> Our intern dev swears this app’s secure...
+
+This was a web challenge with an account creation form. Let's fire up Burp. The account creation request didn't seem suspicious for now, so I sent it to the repeater to abuse it some more. The response seemed interesting, the user id was in the query parameter: `GET /profile.php?id=5 HTTP/1.1`. This was a nice candidate for an Insecure Direct Object Reference(IDOR). I tried repeating the request with values from 0-4. The flag was at 1, the admin user's account.
+
+```txt
+mmuctf{1d0r_4dm1n_4cc3ss_1s_c0mpr0m1s3d}
+```
+
+## Ledilect
+
+> Sometimes the path you take is just a jump away.
+
+This was a simple one, I knew what the challenge wanted, but I couldn't get myself to exploit it, definitely a skill issue. The webapp had a landing page that had a button that made this request:
+
+```txt
+GET /portal/jump.php?url=https://example.com HTTP/1.1
+Host: redacted
+User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Language: en-US, en;q=0.5
+Accept-Encoding: gzip, deflate, br
+Connection: keep-alive
+Referer: redacted
+Cookie: PHPSESSID=ce7743f6cd447d7a1ee94e230c3d9cdb
+Upgrade-Insecure-Requests: 1
+Priority: u=0, i
+```
+
+Looking at that, I suspected an open redirect vulnerability, but I don't know anything about this bug class. I let it rest.
+
+## Meet my X
+
+> In the�days оf cοmfort i met this girl at the Jobless соrner. Аt the�doоrs and windows of iddleness i approached, oops she smiled and thats how i knew she was the one. I guess thatsss whyyy i learned on getting Flags because be warned she later left me at first it feels like a green flag i guess no life was there on blood(heart_break)
+
+This challenge involved homoglyphs, a character or a sequence of characters that looks very similar or identical to another character or sequence of characters, but has a different meaning, encoding, or origin.
+
+A sentence might look normal, but if you copy it into a text editor that shows Unicode details or a specialized homoglyph detector, you'll see different underlying character codes.
+
+I used these online decoders, and to get the flag:
+
+```txt
+mmuctf{oops_twitter_steg_1s_fun}
+```
+
+## Shadow
+
+> Look beyond the appearance, perhaps their numerical essence will guide you to the flag.
+> Can you reveal what lurks in the shadow?
+
+This was another stego challenge; there is an image with what looks like a color palette. The description hints at 'numerical essence', so it might be something to deal with the hex values of the colors. I used this site to extract the hex values.
+
+```txt
+#6d6d75
+#637466
+#7b346c
+#773479
+#355f68
+#316464
+#336e5f
+#316e35
+#64335f
+#6d337d
+```
+
+Decoded becomes
+
+```txt
+mmuctf{4lw4y5_h1dd3n_1n5d3_m3}
+```
+
+## Revealme
+
+> We found this mysterious executable on an old USB stick... Can you figure out how to get it to reveal the flag?
+
+The provided file is an ELF executable binary.
+
+```zsh
+┌──(mockingspectre㉿blackout)-[~/ctf/mmuctf2025]
+└─$ file revealme
+revealme: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d8546bb2c10c0226384fb2771684af9bc150b55e, for GNU/Linux 3.2.0, stripped
+```
+
+```zsh
+┌──(mockingspectre㉿blackout)-[~/ctf/mmuctf2025]
+└─$ checksec --file=revealme
+RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
+Partial RELRO No canary found NX enabled PIE enabled No RPATH No RUNPATH No Symbols No 0 2 revealme
+```
+
+Opening it with Binary Ninja gives us a quick win:
+
+```asm
+00401179 int32_t main(int32_t argc, char** argv, char** envp)
+
+
+00401179 55 push rbp {__saved_rbp}
+0040117a 4889e5 mov rbp, rsp {__saved_rbp}
+0040117d 4883ec70 sub rsp, 0x70
+00401181 488d05800e0000 lea rax, [rel data_402008]
+00401188 4889c7 mov rdi, rax {data_402008, "Enter the secret passphrase: "}
+0040118b b800000000 mov eax, 0x0
+00401190 e8abfeffff call printf
+00401195 488b15a42e0000 mov rdx, qword [rel stdin]
+0040119c 488d4590 lea rax, [rbp-0x70 {buf}]
+004011a0 be64000000 mov esi, 0x64
+004011a5 4889c7 mov rdi, rax {buf}
+004011a8 e8b3feffff call fgets
+004011ad 488d4590 lea rax, [rbp-0x70 {buf}]
+004011b1 488d156e0e0000 lea rdx, [rel data_402026]
+004011b8 4889d6 mov rsi, rdx {data_402026}
+004011bb 4889c7 mov rdi, rax {buf}
+004011be e88dfeffff call strcspn
+004011c3 c644059000 mov byte [rbp+rax-0x70 {buf}], 0x0
+004011c8 488d4590 lea rax, [rbp-0x70 {buf}]
+004011cc 488d15550e0000 lea rdx, [rel data_402028]
+004011d3 4889d6 mov rsi, rdx {data_402028, "OpenSesame123!"}
+004011d6 4889c7 mov rdi, rax {buf}
+004011d9 e892feffff call strcmp
+004011de 85c0 test eax, eax
+004011e0 7511 jne 0x4011f3
+
+
+004011e2 488d054f0e0000 lea rax, [rel data_402038]
+004011e9 4889c7 mov rdi, rax {data_402038, "Correct! The flag is: mmuctf{r3v3rs1ng_st4rt3r}"}
+004011ec e83ffeffff call puts
+004011f1 eb0f jmp 0x401202
+
+
+004011f3 488d056e0e0000 lea rax, [rel data_402068]
+004011fa 4889c7 mov rdi, rax {data_402068, "Nope, try again."}
+004011fd e82efeffff call puts
+
+
+00401202 b800000000 mov eax, 0x0
+00401207 c9 leave {__saved_rbp}
+00401208 c3 retn {__return_addr}
+```
+
+Flag:
+
+```txt
+mmuctf{r3v3rs1ng_st4rt3r}
+```
+
+## Flicker
+
+> An ordinary looking Android app... or is it?
+
+The provided app is an Android APK. Let's fire up jadx-gui. The package name is `com.example.blink`. There is an interesting class `r2d2`. In the onCreate method, there is an image string variable that seems to contain base64 image data.
+
+```zsh
+┌──(mockingspectre㉿blackout)-[~/ctf/mmuctf2025]
+└─$ cat output.txt | base64 -d > decoded_image.png
+```
+
+flag:
+
+```txt
+CTF{PUCKMAN}
+```
+
+## Open_Secrets
+
+> Someone trusted the wrong site and network didn’t forget. Can you piece together what was left behind?
+> Some people still think locks are optional on digital doors.\*
+
+The provided file was a network capture pcap file. For people who don't know, pcap (a packet capture) consists of an application programming interface (API) for capturing network traffic.The challenge title and filename hint at unencrypted traffic. Open up Wireshark and apply an HTTP filter. There is an HTTP stream that leaks the flag:
+
+```txt
+mmuctf{plaintext_login_leak}
+```
+
+## C-x C-s
+
+> Ugh, I keep typing ^x ^s in my shell instead of saving, should’ve stuck with Emacs
+
+This one made me mad. I thought I had the flag, but I couldn't get it. The provided file is a PCAP file. Another network forensics challenge, or so I thought.
+
+opened the file with Wireshark packet and noticed a new kind of communication, to be honest, I didn't know this was possible until I understood what was happening...
+
+I found some articles dealing with this
+
+-
+-
+-
+
+The source and destination use object IDs for communication, something I gathered when reading about the SNMP
+protocol, USB(Universal Serial Bus)
+it's apparent I'm not dealing with any 802.x traffic
+
+Interrupts happen whenever you press a key or click a button, anything that "interrupts" the CPU, after which it has to process your input. Each URB_INTERRUPT in the file corresponds to a key pressed, and the Leftover Capture Data field shows the hex value of the key in 8-byte format.
+
+Creating a filter to list all interrupt communication with non-empty 8 bytes
+
+```txt
+usb.transfer_type == 0x01
+```
+
+```txt
+usb.transfer_type == 0x01 && usb.dst == "host" && !(usb.capdata == 00:00:00:00:00:00:00:00)
+```
+
+Crafting a tshark command to get the leftover capture data for the above filters and redirect it into a file
+
+```zsh
+tshark -r log.pcap -Tfields -Eseparator=, -e thekey.pcapng -Y 'usb.transfer_type == 0x01 && usb.dst == "host" && !(usb.capdata == 00:00:00:00:00:00:00:00)' | sed 's/://g' > usb.capdata
+```
+
+```zsh
+┌──(mockingspectre㉿blackout)-[~/ctf/mmuctf2025]
+└─$ tshark -r thekey.pcapng -Tfields -Eseparator=, -e usb.capdata -Y 'usb.transfer_type == 0x01 && usb.dst == "host" && !(usb.capdata == 00:00:00:00:00:00:00:00)' | sed 's/://g' > usb.capdata
+
+┌──(mockingspectre㉿blackout)-[~/ctf/mmuctf2025]
+└─$ cat usb.capdata
+0000190000000000
+00000c0000000000
+00000c1000000000
+0000102c00000000
+00002c0000000000
+0000090000000000
+00000f0000000000
+0000040000000000
+0000040a00000000
+................
+```
+
+Python script to decode the hex values to strings:
+
+```python
+keyboard = {
+ 2: "PostFail", 4: "a", 5: "b", 6: "c", 7: "d", 8: "e", 9: "f", 10: "g", 11: "h", 12: "i", 13: "j", 14: "k", 15: "l", 16: "m", 17: "n", 18: "o", 19: "p", 20: "q", 21: "r", 22: "s", 23: "t", 24: "u", 25: "v", 26: "w", 27: "x", 28: "y", 29: "z", 30: "1", 31: "2", 32: "3", 33: "4", 34: "5", 35: "6", 36: "7", 37: "8", 38: "9", 39: "0", 40: "Enter", 41: "esc", 2: "del", 43: "tab", 44: "space", 45: "-", 47: "[", 48: "]", 51: "DownArrow", 54: "1", 55: "*", 56: "/", 57: "CapsLock", 79: "RightArrow", 80: "LeftArrow"
+}
+
+
+with open("usb.capdata") as file:
+ i = 1
+ for line in file:
+ bytesArray = bytearray.fromhex(line.strip())
+ for byte in bytesArray:
+ if byte != 0:
+ keyVal = int(byte)
+
+
+ if keyVal in keyboard:
+ print(keyboard[keyVal])
+ else:
+ print("no map found for this value: " + str(keyVal))
+
+
+ i += 1
+```
+
+Running the code outputs what seems to be Vim motions. I wasn't able to decipher this to a correct flag:
+
+```txt
+v
+i
+m
+space
+space
+f
+l
+a
+g
+g
+*
+t
+t
+x
+t
+Enter
+i
+3
+t
+t
+h
+e
+space
+f
+l
+a
+g
+g
+space
+i
+s
+space
+c
+t
+f
+esc
+v
+b
+3
+u
+u
+3
+a
+3
+[
+[
+m
+y
+3
+-
+3
+f
+a
+v
+o
+r
+i
+t
+e
+e
+3
+-
+e
+d
+i
+t
+o
+r
+3
+-
+3
+i
+s
+3
+-
+v
+i
+m
+3
+]
+esc
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+h
+a
+u
+esc
+v
+i
+3
+[
+3
+3
+u
+3
+esc
+3
+DownArrow
+DownArrow
+w
+q
+Enter
+a
+tab
+a
+e
+```
+
+These are the challenges I had the time to tackle. if you have any insights or suggestions. Share them in the comments
diff --git a/content/writing/obsidian-sync.md b/content/writing/obsidian-sync.md
new file mode 100644
index 0000000..fa74abe
--- /dev/null
+++ b/content/writing/obsidian-sync.md
@@ -0,0 +1,116 @@
+---
+title: "Setting up Obsidian sync in Windows"
+description: "Syncing Obsidian in Windows with Windows Task Scheduler with git"
+date: "2023-10-01"
+tags: ["obsidian", "git", "sync", "windows", "cron", "task-scheduler", "powershell"]
+---
+
+Syncing Obsidian in Windows with Windows Task Scheduler and git
+
+[Obsidian](https://obsidian.md/) is a powerful note-taking and knowledge management tool that has gained a dedicated following among researchers, writers, and knowledge workers. To make the most of Obsidian, it's essential to keep your notes synchronized across devices and ensure your data is regularly backed up.Obsidian is the private and flexible writing app that adapts to the way you think.
+
+Obsidian is free for personal use.It does not charge based on features or usage.You only pay if you use Obsidian commercially.
+
+In this article, we'll guide you through the process of setting up automated synchronization for your Obsidian vault on Windows using Windows Task Scheduler and a PowerShell script.[^note]
+
+## Prerequisites
+
+Before we dive into setting up the synchronization task, ensure you have the following prerequisites in place:
+
+1. **Obsidian Installed:** Make sure Obsidian is [installed](https://obsidian.md/download) on your Windows computer, and you have an existing Obsidian vault that you want to sync.
+
+1. **Git Installed:** You'll need Git installed and configured with your Obsidian vault's repository. If you haven't already done this, you can download Git from the [official website](https://git-scm.com/downloads) and follow the installation instructions.
+
+1. **PowerShell Script:** The provided PowerShell script, sync.ps1, should be located in your Obsidian vault folder.
+
+## Understanding the PowerShell Script
+
+The provided PowerShell script, sync.ps1, is the heart of our synchronization task. It automates the process of committing changes in your Obsidian vault's Git repository and pushing them to your remote repository (e.g., GitHub or GitLab). Here's a brief overview of the script:
+
+```ps1
+# Define the folder path
+$FolderPath = "C:\path\to\obsidian-vault"
+
+# Change directory to the repository folder
+Set-Location -Path $FolderPath
+
+# Check if the working tree is clean
+$IsClean = (git diff-index --quiet HEAD --) -or (git diff-files --quiet)
+
+if ($IsClean) {
+ Write-Host "Working tree is clean. Skipping commit and pushing changes."
+ git push
+} else {
+ # Get the current date in the desired format (Day - Date)
+ $CommitMessage = "$(Get-Date -Format 'dddd - yyyy-MM-dd HH:mm:ss')"
+
+ # Commit the changes
+ git add .
+ git commit -m $CommitMessage
+
+ # Push the changes
+ git push
+}
+```
+
+This script does the following:
+
+- Sets the folder path to your Obsidian vault.
+- Checks if there are any changes to commit. If the vault is clean (no changes), it skips the commit and only pushes changes.
+- If there are changes, it commits them with a timestamped message and then pushes them to the remote repository.
+
+## Setting up Windows Task Scheduler
+
+Now that we have our PowerShell script ready, let's set up a scheduled task using Windows Task Scheduler to automate the synchronization process. Follow these steps:
+
+1. **Open an Elevated PowerShell Prompt:** To run the necessary commands, open PowerShell as an administrator.
+
+1. **Define Task Variables:** Execute the following commands to define variables for your task:
+
+ ```ps1
+ $ScriptPath = "C:\path\to\obsidian-vault\sync.ps1"
+ $TaskName = "obsidian-sync"
+ $UserAccount = "$env:USERDOMAIN\$env:USERNAME"
+ ```
+
+ Replace $ScriptPath with the actual path to your sync.ps1 script, $TaskName with a name for your task.
+
+1. **Configure Task Trigger:** Set up a trigger for your task. In this example, we'll schedule the task to run daily at 9:00 PM:
+
+ ```ps1
+ $Trigger = New-ScheduledTaskTrigger -Daily -At '9:00 PM'
+ ```
+
+ You can adjust the schedule according to your preference.
+
+1. Define Task Principal and Settings: Configure the task's principal (the user account under which the task will run) and settings:
+
+ ```ps1
+ $Principal = New-ScheduledTaskPrincipal -UserId $UserAccount -RunLevel Highest
+ $Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -RunOnlyIfNetworkAvailable -WakeToRun
+ ```
+
+ These settings ensure that the task runs with the necessary privileges and conditions.
+
+1. **Define Task Action:** Specify the action that the task will perform, which is running the PowerShell script:
+
+ ```ps1
+ $Action = New-ScheduledTaskAction -Execute 'PowerShell.exe' -Argument "-ExecutionPolicy Bypass -WindowStyle Hidden -File `"$ScriptPath`""
+ ```
+
+ This action runs PowerShell with the provided script.
+
+1. **Create the Scheduled Task:** Finally, create the scheduled task and register it with Windows Task Scheduler:
+
+ ```ps1
+ $Task = New-ScheduledTask -Action $Action -Trigger $Trigger -Principal $Principal -Settings $Settings
+ Register-ScheduledTask -TaskName $TaskName -InputObject $Task
+ ```
+
+The Obsidian synchronization task is now set up and ready to run automatically based on the schedule you defined.
+
+# Inspiration
+
+When looking up on how to implement this I found some breakthrough from this [stack overflow](https://stackoverflow.com/questions/7195503/setting-up-a-cron-job-in-windows) post. There are suggestions on how to do this using cron jobs in wsl. They are worth a look at. This article on [powershell](https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtask?view=windowsserver2022-ps) with windows server was also helpful.
+
+[^note]: This method is only optimal for desktop sync. To sync across devices obsidian has a paid plan that has some extra features Such as Sync notes across devices, End-to-end encryption, Version history, Priority email support. Consider checking it out at [https://obsidian.md/pricing](https://obsidian.md/pricing)
diff --git a/content/writing/scriptctf2025.md b/content/writing/scriptctf2025.md
new file mode 100644
index 0000000..2849399
--- /dev/null
+++ b/content/writing/scriptctf2025.md
@@ -0,0 +1,786 @@
+---
+title: "ScriptCTF 2025 Writeup"
+description: "ScriptCTF 2025 Writeup"
+date: "2025-08-18"
+tags: ["ctf", "rev", "web", "forensics"]
+---
+
+![ScriptCTF mascot illustration of a wizard coding at a laptop, with the tagline "scriptCTF makes CTFs fun and approachable for all skill levels!"][image1]
+Over the weekend, I participated in ScriptCTF, a capture-the-flag competition packed with diverse challenges spanning cryptography, forensics, reverse engineering, and web exploitation.
+
+In this write-up, I’ll walk through some of the problems I solved, breaking down my approach, the tools I used, and the reasoning behind each step. Rather than just dropping final answers, my goal is to document the problem-solving process in a way that’s reproducible and useful for others looking to sharpen their cybersecurity skills.
+
+# Challenge: Renderer
+
+![ScriptCTF challenge card for "Renderer" describing the free image-rendering app and its chall.zip attachment][image2]
+
+This is the first web challenge; it launches an instance, and the source code is provided for manual code review. There are three important files: two Jinja templates and a Python file.
+
+upload.html
+
+```html
+
+
+
+ Upload Image
+
+
+
Upload Images
+
This free to use website allows you to render your images!