<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xml" href="https://blog.sayan.page/feed.xslt.xml"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://blog.sayan.page/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.sayan.page/" rel="alternate" type="text/html" /><updated>2026-07-23T07:40:42+01:00</updated><id>https://blog.sayan.page/feed.xml</id><title type="html">Sayan’s Blog</title><subtitle>My writing focusses on machine learning, computer science and other topics that catch my fancy.</subtitle><author><name>Sayan Goswami</name></author><entry><title type="html">Engineering Transformers</title><link href="https://blog.sayan.page/transformers-notes/" rel="alternate" type="text/html" title="Engineering Transformers" /><published>2026-07-06T00:00:00+01:00</published><updated>2026-07-06T00:00:00+01:00</updated><id>https://blog.sayan.page/transformers-notes</id><content type="html" xml:base="https://blog.sayan.page/transformers-notes/"><![CDATA[<p>Various notes on engineering with Transformers.</p>

<h2 class="no_toc" id="index">Index</h2>

<ul id="markdown-toc">
  <li><a href="#mixture-of-experts" id="markdown-toc-mixture-of-experts">Mixture of Experts</a></li>
  <li><a href="#faster-inference" id="markdown-toc-faster-inference">Faster Inference</a>    <ul>
      <li><a href="#speculative-decoding" id="markdown-toc-speculative-decoding">Speculative decoding</a></li>
      <li><a href="#prefill-decode-disaggregation" id="markdown-toc-prefill-decode-disaggregation">Prefill decode disaggregation</a></li>
      <li><a href="#paged-attention" id="markdown-toc-paged-attention">Paged attention</a></li>
      <li><a href="#prefix-caching" id="markdown-toc-prefix-caching">Prefix caching</a></li>
      <li><a href="#kv-cache-offloading" id="markdown-toc-kv-cache-offloading">KV cache offloading</a></li>
    </ul>
  </li>
</ul>

<hr />

<h2 id="mixture-of-experts">Mixture of Experts</h2>

<ul>
  <li>Helps scale model size without increasing FLOPs</li>
  <li>Dipatch to expert works with
    <ul>
      <li>Learned routing (<a href="https://arxiv.org/abs/2101.03961">Switch Transformers</a>)</li>
      <li>Randomly (with capacity cap, <a href="https://arxiv.org/abs/2006.16668">GShard</a>)</li>
      <li>Hashing (baseline, not learned)</li>
    </ul>
  </li>
  <li>HF <a href="https://huggingface.co/blog/moe">blog post</a> on MoE</li>
  <li>MoE is typically applied to MLP layers but can also be applied to attention heads
    <ul>
      <li><a href="https://arxiv.org/abs/2306.04640">ModuleFormer</a></li>
      <li><a href="https://arxiv.org/abs/2404.07413">JeTMoE</a></li>
    </ul>
  </li>
</ul>

<h2 id="faster-inference">Faster Inference</h2>

<h3 id="speculative-decoding"><a href="https://handbook.modular.com/inference-optimization/speculative-decoding/">Speculative decoding</a></h3>

<ul>
  <li>Use a smaller model to predict next k-tokens and then run a batch of k trajectories with the larger model (in parallel)</li>
  <li>Inference is memory bound, running 1 prediction takes the same time as k concurrent ones</li>
  <li>Methods
    <ul>
      <li>Medusa: multiple light weight prediction heads that predict future tokens</li>
      <li>Multi-token prediction: predict multiple tokens at each inference step</li>
      <li>N-gram speculation: based off of current context</li>
      <li><a href="https://arxiv.org/abs/2401.15077">EAGLE</a>: perdict next hidden state instead of next token and then uses the same head for prediction. Very strong!</li>
      <li><a href="https://arxiv.org/pdf/2607.05147">DSpark</a>: from DeepSeek V4; dynamic verification length, parallel backbone + sequential for dependencies when drafting + per-position confidence predictions.</li>
    </ul>
  </li>
</ul>

<h3 id="prefill-decode-disaggregation"><a href="https://handbook.modular.com/inference-optimization/prefill-decode-disaggregation/">Prefill decode disaggregation</a></h3>

<ul>
  <li>Prefill: Compute bound; mostly computation of large matmuls to store in KV cache</li>
  <li>Decode: Memry bound; retrieval and storage of KV cache + some compute</li>
  <li>Longer multi-turn sessions = more resuse of KV cache</li>
  <li>Mostly useful for heterogenous compute (high HBM v/s faster compute)</li>
  <li>This only helps when communication (network, disk, memory etc) overhead is lesser than prefilling locally at the inference node</li>
  <li>vLLM <a href="https://docs.vllm.ai/en/stable/examples/disaggregated/lmcache/">supports disaggregated prefilling</a> with LMCache.</li>
</ul>

<h3 id="paged-attention"><a href="https://arxiv.org/abs/2309.06180">Paged attention</a></h3>

<ul>
  <li>KV cache is normally store as a contiguous block of memory.</li>
  <li>This is wasteful as not all sequences use up the entire context window.</li>
  <li>This leads to lower effective batch size and memory fragmentation.</li>
  <li>With paged attention, KV cache is stored as smaller pages and retrieved on the fly with a lookup table.</li>
</ul>

<h3 id="prefix-caching">Prefix caching</h3>

<ul>
  <li>Store KV cache of an exisiting query to reduce latency.</li>
  <li>Helps with things such as system prompt, multi-turn conversation.</li>
  <li>Essentially helps reduce prefill with stored caches across multiple requests.</li>
</ul>

<h3 id="kv-cache-offloading">KV cache offloading</h3>

<ul>
  <li>KV cache size grows linearly with sequence length.</li>
  <li>User interactions are mostly sparse, KV caches for all requests don’t need to stay in HBM all the time.</li>
  <li>Unused KV cache can be paged out to host RAM or even persistent storage and then paged in when required.</li>
  <li>vLLM <a href="https://docs.vllm.ai/en/stable/examples/disaggregated/lmcache/">supports offloading</a> with LMCache.</li>
</ul>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[Various notes on engineering with Transformers.]]></summary></entry><entry><title type="html">Undervolting the Steam Deck</title><link href="https://blog.sayan.page/undervolt-steam-deck/" rel="alternate" type="text/html" title="Undervolting the Steam Deck" /><published>2026-05-01T00:00:00+01:00</published><updated>2026-05-01T00:00:00+01:00</updated><id>https://blog.sayan.page/undervolt-steam-deck</id><content type="html" xml:base="https://blog.sayan.page/undervolt-steam-deck/"><![CDATA[<p>Undervolting the Steam Deck can make it run more efficiently and extend its battery life. Here’s the setup I used.</p>

<h2 id="steps">steps</h2>

<ol>
  <li>power off the Steam Deck</li>
  <li>hold the volume up and power buttons until you hear a chime</li>
  <li>you’ll now be in the BIOS
  <img src="/images/steam-deck/deck-bios.jpeg" alt="Steam Deck showing the InsydeH2O BIOS main menu with options for Continue, Boot Manager, Boot From File, and Setup Utility" /></li>
  <li>from here go to the menu item titled “Setup Utility”</li>
  <li>once there, navigate to the “Advanced Settings” section
  <img src="/images/steam-deck/deck-undervolt.jpeg" alt="Steam Deck BIOS advanced settings screen showing CPU and GPU voltage offsets set to -50 mV and SOC voltage offset set to -30 mV" /></li>
  <li>here you can choose voltages offset from 0mV to -50mV for the CPU, GPU and SoC</li>
  <li>I decided to use -50mV offset on both the CPU and the GPU and kept the SoC at -30mV</li>
</ol>

<p>That’s it, happy gaming!</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[Undervolting the Steam Deck can make it run more efficiently and extend its battery life. Here’s the setup I used.]]></summary></entry><entry><title type="html">Porting GPT-2 to MLX for fun!</title><link href="https://blog.sayan.page/gpt2-in-mlx/" rel="alternate" type="text/html" title="Porting GPT-2 to MLX for fun!" /><published>2026-04-26T00:00:00+01:00</published><updated>2026-04-26T00:00:00+01:00</updated><id>https://blog.sayan.page/gpt2-in-mlx</id><content type="html" xml:base="https://blog.sayan.page/gpt2-in-mlx/"><![CDATA[<h2 id="what-is-mlx">what is MLX?</h2>

<p>MLX is an array framework purpose built for Apple Silicon; think NumPy but tuned more for Apple’s hardware.
It also has higher level abstractions that provide an interface that’s similar to PyTorch.
I wanted to learn MLX, what better way to do than to port <a href="https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf">the model</a> that started it all for LLMs.</p>

<h2 id="the-constituents-of-a-gpt">the constituents of a GPT</h2>

<p>GPT is a decoder only transformer, meaning it goes from a sequence of embedded tokens and then auto-regressively generates a sequence from this pre-fill.
It also uses positional embeddings to encode the position of tokens in a sequence.</p>

<p>Each <a href="https://github.com/say4n/mlxgpt/blob/d16dd66dc75f9f96766296efb444a8cbc66d3924/model.py#L81">decomposable block</a> is composed of causal (masked) multi-headed self attention, MLP and pre-layer norms for both. This block is then stacked multiple times in series.</p>

<p><a href="https://github.com/say4n/mlxgpt/blob/d16dd66dc75f9f96766296efb444a8cbc66d3924/model.py#L119">Finally</a>, a layer norm and an LM head transforms the hidden dim back up to the vocab size of the tokenizer. This can then be decoded by treating the outputs as logits.</p>

<h2 id="loading-pre-trained-weights-from-hf-transformers">loading pre-trained weights from HF Transformers</h2>

<p>Mostly boring stuff here, this involves loading the model weights from the HF Transformers library and then renaming the <code class="language-plaintext highlighter-rouge">state_dict</code> keys <a href="https://github.com/say4n/mlxgpt/blob/d16dd66dc75f9f96766296efb444a8cbc66d3924/model.py#L145">into a form that</a> can be used with MLX.</p>

<h2 id="improving-generation-with-sampling">improving generation with sampling</h2>

<p>Greedy decoding produces the same sequence by picking the most likely outcome every time.
This can be improved by introducing two parameteres <code class="language-plaintext highlighter-rouge">temperature</code> and <code class="language-plaintext highlighter-rouge">top_k</code> alongside sampling to improve the diversity of generated sequences.
The <code class="language-plaintext highlighter-rouge">temperature</code> parameter controls the sharpness of the probability distrbution of the tokens whereas the <code class="language-plaintext highlighter-rouge">top_k</code> parameter controls for how many of the options are considered while sampling.
Setting a <code class="language-plaintext highlighter-rouge">temperature</code> of 0 <a href="https://github.com/say4n/mlxgpt/blob/d16dd66dc75f9f96766296efb444a8cbc66d3924/model.py#L165">falls back to</a> greedy decoding.</p>

<h2 id="whats-next">what’s next?</h2>

<p>Lots of ideas to try! Here’s a couple of them in no particular order:</p>
<ul>
  <li>Instruction tuned weights for GPT-2</li>
  <li>Training/fine-tuning GPT-2 for some niche task</li>
  <li>Implementing other LLMs such as Llama</li>
</ul>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[what is MLX?]]></summary></entry><entry><title type="html">Using OpenCode with local LLMs via LM Studio</title><link href="https://blog.sayan.page/opencode-local-llms-lmstudio/" rel="alternate" type="text/html" title="Using OpenCode with local LLMs via LM Studio" /><published>2026-01-28T00:00:00+00:00</published><updated>2026-01-28T00:00:00+00:00</updated><id>https://blog.sayan.page/opencode-local-llms-lmstudio</id><content type="html" xml:base="https://blog.sayan.page/opencode-local-llms-lmstudio/"><![CDATA[<p><a href="https://opencode.ai">OpenCode</a> is an open source, terminal-based AI coding assistant – think Claude Code or Cursor but you can hook it up to your own models. By default it uses cloud providers, but the interesting bit is pairing it with <a href="https://lmstudio.ai">LM Studio</a> to run everything locally.</p>

<h2 id="install-opencode">install opencode</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-fsSL</span> https://opencode.ai/install | bash
opencode <span class="nt">--version</span>
</code></pre></div></div>

<p>Config lives in <code class="language-plaintext highlighter-rouge">~/.config/opencode/</code>.</p>

<h2 id="point-it-at-lm-studio">point it at LM Studio</h2>

<p>Fire up LM Studio and load a code-focused model – something like Qwen3 Coder 30B works well if your hardware can handle it. Make sure the local server is running, by default it listens on <code class="language-plaintext highlighter-rouge">http://localhost:1234</code>.</p>

<p>Then edit <code class="language-plaintext highlighter-rouge">~/.config/opencode/opencode.json</code>:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"$schema"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://opencode.ai/config.json"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"provider"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"lmstudio"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nl">"npm"</span><span class="p">:</span><span class="w"> </span><span class="s2">"@ai-sdk/openai-compatible"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LM Studio (local)"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"options"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"baseURL"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://localhost:1234/v1"</span><span class="w">
            </span><span class="p">},</span><span class="w">
            </span><span class="nl">"models"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"zai-org/glm-4.7-flash"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                    </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"glm-4.7-flash"</span><span class="w">
                </span><span class="p">}</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>The key bit is <code class="language-plaintext highlighter-rouge">@ai-sdk/openai-compatible</code> – LM Studio exposes an OpenAI-compatible API, so this just works.</p>

<p>Launch <code class="language-plaintext highlighter-rouge">opencode</code> and run <code class="language-plaintext highlighter-rouge">/model</code> to verify. You should see “LM Studio (local)” as an available provider.</p>

<h2 id="why-this-matters">why this matters</h2>

<p>The nice thing about running everything locally is that your code never leaves your machine, there are no token limits, no API costs, and it works offline. The tradeoff is output quality – local models are getting better fast but still lag behind frontier cloud models for complex reasoning. For code review, refactoring suggestions, and boilerplate generation though, they work surprisingly well.</p>

<h2 id="references">references</h2>

<ul>
  <li><a href="https://opencode.ai">OpenCode</a></li>
  <li><a href="https://lmstudio.ai">LM Studio</a></li>
  <li><a href="https://medium.com/@linc89617/automating-code-security-review-a-practical-guide-to-opencode-lm-studio-03ea7f98ca6d">Yoyo Lin’s guide on OpenCode + LM Studio for security review</a></li>
</ul>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[OpenCode is an open source, terminal-based AI coding assistant – think Claude Code or Cursor but you can hook it up to your own models. By default it uses cloud providers, but the interesting bit is pairing it with LM Studio to run everything locally.]]></summary></entry><entry><title type="html">TIL: `ctop` - think `top` but for containers</title><link href="https://blog.sayan.page/til-ctop/" rel="alternate" type="text/html" title="TIL: `ctop` - think `top` but for containers" /><published>2025-12-13T00:00:00+00:00</published><updated>2025-12-13T00:00:00+00:00</updated><id>https://blog.sayan.page/til-ctop</id><content type="html" xml:base="https://blog.sayan.page/til-ctop/"><![CDATA[<p>See: <a href="https://ctop.sh/">https://ctop.sh/</a>, described as:</p>

<blockquote>
  <p>concise commandline monitoring for containers</p>
</blockquote>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[See: https://ctop.sh/, described as:]]></summary></entry><entry><title type="html">How to compute the size of Pytorch tensors</title><link href="https://blog.sayan.page/computing-size-of-tensors/" rel="alternate" type="text/html" title="How to compute the size of Pytorch tensors" /><published>2025-11-28T00:00:00+00:00</published><updated>2025-11-28T00:00:00+00:00</updated><id>https://blog.sayan.page/computing-size-of-tensors</id><content type="html" xml:base="https://blog.sayan.page/computing-size-of-tensors/"><![CDATA[<p>It is fairly simple to compute the in memory size of Pytorch tensors with two handy methods: <a href="https://docs.pytorch.org/docs/stable/generated/torch.numel.html#torch-numel"><code class="language-plaintext highlighter-rouge">numel</code></a> and <a href="https://docs.pytorch.org/docs/stable/generated/torch.Tensor.element_size.html#torch-tensor-element-size"><code class="language-plaintext highlighter-rouge">element_size</code></a>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kn">import</span> <span class="n">torch</span>

<span class="k">def</span> <span class="nf">get_size</span><span class="p">(</span><span class="n">t</span><span class="p">:</span> <span class="n">torch</span><span class="p">.</span><span class="n">Tensor</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">t</span><span class="p">.</span><span class="nf">numel</span><span class="p">()</span> <span class="o">*</span> <span class="n">t</span><span class="p">.</span><span class="nf">element_size</span><span class="p">()</span>

</code></pre></div></div>

<p>That’s it!</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[It is fairly simple to compute the in memory size of Pytorch tensors with two handy methods: numel and element_size:]]></summary></entry><entry><title type="html">Reverse engineering PCB schematics using willpower and some sand paper!</title><link href="https://blog.sayan.page/reverse-engineering-pcbs/" rel="alternate" type="text/html" title="Reverse engineering PCB schematics using willpower and some sand paper!" /><published>2025-08-25T00:00:00+01:00</published><updated>2025-08-25T00:00:00+01:00</updated><id>https://blog.sayan.page/reverse-engineering-pcbs</id><content type="html" xml:base="https://blog.sayan.page/reverse-engineering-pcbs/"><![CDATA[]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Why does every browser pretend to be Mozilla?</title><link href="https://blog.sayan.page/the-mess-with-browser-user-agents/" rel="alternate" type="text/html" title="Why does every browser pretend to be Mozilla?" /><published>2025-06-23T00:00:00+01:00</published><updated>2025-06-23T00:00:00+01:00</updated><id>https://blog.sayan.page/the-mess-with-browser-user-agents</id><content type="html" xml:base="https://blog.sayan.page/the-mess-with-browser-user-agents/"><![CDATA[]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">I’ve finally completed GTA V</title><link href="https://blog.sayan.page/gta-v-complete/" rel="alternate" type="text/html" title="I’ve finally completed GTA V" /><published>2025-02-11T00:00:00+00:00</published><updated>2025-02-11T00:00:00+00:00</updated><id>https://blog.sayan.page/gta-v-complete</id><content type="html" xml:base="https://blog.sayan.page/gta-v-complete/"><![CDATA[<p>12 years after launch, I’ve finally completed the story mode of GTA V.</p>

<p><img src="/images/gta-v.png" alt="Franklin, Michael &amp; Lamar after the final story mode mission of GTA V" /></p>

<p>It was a nice game but it did not really last for as long as I had hoped for.</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[12 years after launch, I’ve finally completed the story mode of GTA V.]]></summary></entry><entry><title type="html">How to subscribe to GitHub Gists Atom feeds</title><link href="https://blog.sayan.page/gist-rss-feed/" rel="alternate" type="text/html" title="How to subscribe to GitHub Gists Atom feeds" /><published>2025-01-21T00:00:00+00:00</published><updated>2025-01-21T00:00:00+00:00</updated><id>https://blog.sayan.page/gist-rss-feed</id><content type="html" xml:base="https://blog.sayan.page/gist-rss-feed/"><![CDATA[<p>While reading <a href="https://gist.github.com/hackermondev/45a3cdfa52246f1d1201c1e8cdef6117">hackermondevs writeup</a> on deanonymization attacks, I wondered if it was possible to subscribe to a Atom/RSS feed of GitHub Gists.</p>

<p>You can, just add .atom to the original URL of the Gist profile and et voilà!</p>

<p>More verbosely, subscribe to <code class="language-plaintext highlighter-rouge">https://gist.github.com/{username}.atom</code> from your feed reader of choice.</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[While reading hackermondevs writeup on deanonymization attacks, I wondered if it was possible to subscribe to a Atom/RSS feed of GitHub Gists.]]></summary></entry><entry><title type="html">Time Machine backups over SMB</title><link href="https://blog.sayan.page/time-machine-backup-smb/" rel="alternate" type="text/html" title="Time Machine backups over SMB" /><published>2024-12-20T00:00:00+00:00</published><updated>2024-12-20T00:00:00+00:00</updated><id>https://blog.sayan.page/time-machine-backup-smb</id><content type="html" xml:base="https://blog.sayan.page/time-machine-backup-smb/"><![CDATA[]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">TIL: Firecracker VM</title><link href="https://blog.sayan.page/til-firecracker-vm/" rel="alternate" type="text/html" title="TIL: Firecracker VM" /><published>2024-12-03T00:00:00+00:00</published><updated>2024-12-03T00:00:00+00:00</updated><id>https://blog.sayan.page/til-firecracker-vm</id><content type="html" xml:base="https://blog.sayan.page/til-firecracker-vm/"><![CDATA[<p>TIL about <a href="https://firecracker-microvm.github.io">Firecracker VM</a>, the underlying software powering AWS Lambdas and Fargate.</p>

<blockquote>
  <p>Firecracker is an open source virtualization technology that is purpose-built for creating and managing secure, multi-tenant container and function-based services.</p>
</blockquote>

<blockquote>
  <p>Firecracker enables you to deploy workloads in lightweight virtual machines, called microVMs, which provide enhanced security and workload isolation over traditional VMs, while enabling the speed and resource efficiency of containers.</p>
</blockquote>

<blockquote>
  <p>Firecracker is a virtual machine monitor (VMM) that uses the Linux Kernel-based Virtual Machine (KVM) to create and manage microVMs.</p>
</blockquote>

<blockquote>
  <p>Firecracker is generally available on 64-bit Intel, AMD and Arm CPUs with support for hardware virtualization. 🤯</p>
</blockquote>

<p>Julia Evans has a fantastic post on the same: <a href="https://jvns.ca/blog/2021/01/23/firecracker--start-a-vm-in-less-than-a-second/">Firecracker: start a VM in less than a second</a>, you should give it a read!</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[TIL about Firecracker VM, the underlying software powering AWS Lambdas and Fargate.]]></summary></entry><entry><title type="html">TIL: V8 Isolates</title><link href="https://blog.sayan.page/til-v8-isolate/" rel="alternate" type="text/html" title="TIL: V8 Isolates" /><published>2024-12-03T00:00:00+00:00</published><updated>2024-12-03T00:00:00+00:00</updated><id>https://blog.sayan.page/til-v8-isolate</id><content type="html" xml:base="https://blog.sayan.page/til-v8-isolate/"><![CDATA[<p>While reading <a href="https://developers.cloudflare.com/workers/reference/how-workers-works/#isolates">How Workers works</a> on Cloudflare’s blog, I learned about V8 Isolates.</p>

<blockquote>
  <p>V8 orchestrates isolates: lightweight contexts that provide your code with variables it can access and a safe environment to be executed within. You could even consider an isolate a sandbox for your function to run in.</p>

  <p>A single instance of the runtime can run hundreds or thousands of isolates, seamlessly switching between them. Each isolate’s memory is completely isolated, so each piece of code is protected from other untrusted or user-written code on the runtime. Isolates are also designed to start very quickly. Instead of creating a virtual machine for each function, an isolate is created within an existing environment. This model eliminates the cold starts of the virtual machine model.</p>
</blockquote>

<p>That reads suspiciously like threads, doesn’t it? Yes, sort of – it depends on the implementation. <a href="https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/bindings/core/v8/V8BindingDesign.md#isolate">This</a> is what Chromium’s Blink has to say:</p>

<blockquote>
  <p>An isolate is a concept of an instance in V8. In Blink, isolates and threads are in 1:1 relationship. One isolate is associated with the main thread. One isolate is associated with one worker thread.</p>
</blockquote>

<p>Anyway, circling back to what Cloudflare workers – I wonder what the implications for security and isolation are across the various isolates? 
There’s various threads of discussion on this, notably <a href="https://news.ycombinator.com/item?id=31759170">this thread</a> from the orange website.
It defers the decision to <em>it depends</em> with process based isolation being preferred when running untrusted code.</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[While reading How Workers works on Cloudflare’s blog, I learned about V8 Isolates.]]></summary></entry><entry><title type="html">RSS feeds can have styles (sort of)</title><link href="https://blog.sayan.page/styling-rss-feeds/" rel="alternate" type="text/html" title="RSS feeds can have styles (sort of)" /><published>2024-12-02T00:00:00+00:00</published><updated>2024-12-02T00:00:00+00:00</updated><id>https://blog.sayan.page/styling-rss-feeds</id><content type="html" xml:base="https://blog.sayan.page/styling-rss-feeds/"><![CDATA[<p>While reading https://boehs.org/node/dark-web-security, I noticed something weird with their blog feed page.</p>

<p><img src="/images/styled-rss-feed.png" alt="styled atom feed page" /></p>

<p>Yep, that’s right – there’s CSS in that Atom feed, turns out you can do it.</p>

<p>Here’s another blog posting describing how: https://andrewstiefel.com/style-atom-xsl/.</p>

<p>And now its in action here: https://blog.sayan.page/feed.xml, that’s all!</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[While reading https://boehs.org/node/dark-web-security, I noticed something weird with their blog feed page.]]></summary></entry><entry><title type="html">How to setup multiple admin accounts on Immich</title><link href="https://blog.sayan.page/immich-multiple-admins/" rel="alternate" type="text/html" title="How to setup multiple admin accounts on Immich" /><published>2024-07-14T00:00:00+01:00</published><updated>2024-07-14T00:00:00+01:00</updated><id>https://blog.sayan.page/immich-multiple-admins</id><content type="html" xml:base="https://blog.sayan.page/immich-multiple-admins/"><![CDATA[<p>This guide assumes you’re running Immich using the <a href="https://immich.app/docs/install/docker-compose">recommended</a> installation method.</p>

<h2 id="connect-to-the-postgress-database-docker-container">connect to the postgress database docker container</h2>

<p><code class="language-plaintext highlighter-rouge">docker exec -it immich_postgres bash</code></p>

<h2 id="connect-to-the-postgress-shell-in-the-container-and-load-the-immich-database">connect to the postgress shell in the container and load the immich database</h2>

<p><code class="language-plaintext highlighter-rouge">psql immich postgres</code></p>

<h2 id="check-which-users-are-currently-admin-users">check which users are currently admin users</h2>

<pre><code class="language-psql">immich=# select email,"isAdmin" from users;
</code></pre>

<h2 id="promote-an-existing-user-to-the-admin-role">promote an existing user to the admin role</h2>

<pre><code class="language-psql">UPDATE users SET "isAdmin"='t' WHERE email='email@example.com';
</code></pre>

<p>And that’s it!</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[This guide assumes you’re running Immich using the recommended installation method.]]></summary></entry><entry><title type="html">Setting up `mitmproxy` on iOS</title><link href="https://blog.sayan.page/mitm-proxy-on-ios/" rel="alternate" type="text/html" title="Setting up `mitmproxy` on iOS" /><published>2024-04-21T00:00:00+01:00</published><updated>2024-04-21T00:00:00+01:00</updated><id>https://blog.sayan.page/mitm-proxy-on-ios</id><content type="html" xml:base="https://blog.sayan.page/mitm-proxy-on-ios/"><![CDATA[<h2 id="install-the-mitmproxy-server">install the <code class="language-plaintext highlighter-rouge">mitmproxy</code> server</h2>

<p>Install the <code class="language-plaintext highlighter-rouge">mitmproxy</code> server on your platform of choice.
The instructions on <a href="https://docs.mitmproxy.org/stable/overview-installation/">mitmproxy.org</a> are fairly straightforward to follow!
After installing, run the <code class="language-plaintext highlighter-rouge">mitmproxy</code> command to start the proxy server.</p>

<p>Note the IP address/hostname (let’s call this <code class="language-plaintext highlighter-rouge">proxyhost</code>) of the computer that is running the proxy server, by default the server listens on port <strong>8080</strong>.
Essentially, we should have the proxy server reachable at <code class="language-plaintext highlighter-rouge">proxyhost:8080</code> now for any device on the same network as the proxy server.</p>

<h2 id="configure-your-ios-device-to-use-the-proxy">configure your iOS device to use the proxy</h2>

<p>Head over to Settings &gt; WiFi and then tap on the (i) icon beside the network your are connected to.</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/0.png">Screenshot 0</a></p>

<p>Scroll down to the bottom of the page and then tap on the option that says “Configure Proxy”.</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/1.png">Screenshot 1</a></p>

<p>Use the proxy server IP and port from earlier (<code class="language-plaintext highlighter-rouge">proxyhost:8080</code>) and hit save.</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/2.png">Screenshot 2</a></p>

<p>Open Safar on the iOS device and head over to <a href="mitm.it">mitm.it</a>.
You will be greeted with a page that lists CA certificates for various platforms, tap on the one that is for iOS.</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/3.png">Screenshot 3</a></p>

<p>Tap on allow to download <code class="language-plaintext highlighter-rouge">mitmproxy</code>’s CA cert to the iOS device’s certificate store.</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/4.png">Screenshot 4</a></p>

<p>Choose the device that you want to install the CA certificate too. Most likely you would want to choose the iPhone from the list.</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/5.png">Screenshot 5</a></p>

<p>The CA certificate for <code class="language-plaintext highlighter-rouge">mitmproxy</code> is now downloaded, we need to head on over to the Settings apps now.</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/6.png">Screenshot 6</a></p>

<p>When you open the Settings app on iOS device, you’ll be greeted with a list item titled “Profile Downloaded”. Tap on that!</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/7.png">Screenshot 7</a></p>

<p>Then tap on the “Install” button on the top right corner.</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/8.png">Screenshot 8</a></p>

<p>After that head on to Settings &gt; General &gt; About and scroll down to the bottom of the page.
You will see a menu item titled “Certificate Trust Settings”.
Tap on it, in the following page enable the certifcate for <code class="language-plaintext highlighter-rouge">mitmproxy</code>.</p>

<p><strong>See</strong>: <a href="/images/mitm-proxy-on-ios/9.png">Screenshot 9</a></p>

<h2 id="profit">profit</h2>

<p>That’s it, you will now be able to intercept SSL traffic from your iOS device on the proxy server.</p>

<h2 id="cleaning-up">cleaning up</h2>

<p>I would recommend disabling or removing the <code class="language-plaintext highlighter-rouge">mitmproxy</code> CA certificate when not in use, you can simply toggle it in Settings &gt; General &gt; About &gt; Certificate Trust Settings.</p>

<p>You would also need to disable the proxy server configuration for the network whenever you turn off the proxy server.
You can do that by heading over to Settings &gt; WiFi and then tap on the (i) icon beside the network your are connected to.
Scroll down to the bottom of the page and then tap on the option that says “Configure Proxy” and then tap on the “Off” option from the list.</p>

<h2 id="caveats">caveats</h2>

<p>You will not be able to interecept SSL traffic for any application that uses certificate pinning.
This is because these applications bypass the system certificate store and have their own trust store for certificates.
See <a href="https://docs.mitmproxy.org/stable/concepts-certificates/#certificate-pinning">https://docs.mitmproxy.org/stable/concepts-certificates/#certificate-pinning</a> on working around certificate pinning.</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[install the mitmproxy server]]></summary></entry><entry><title type="html">Who registers your domain names?</title><link href="https://blog.sayan.page/mark-monitor/" rel="alternate" type="text/html" title="Who registers your domain names?" /><published>2024-03-24T00:00:00+00:00</published><updated>2024-03-24T00:00:00+00:00</updated><id>https://blog.sayan.page/mark-monitor</id><content type="html" xml:base="https://blog.sayan.page/mark-monitor/"><![CDATA[<p>Most of us register and renew our domain names through various registrars such as Namecheap, Godaddy, the <a href="https://support.google.com/domains/answer/13689670">late Google domains</a> etc. 
But how do the fortune 500 companies do it? I am glad you asked!</p>

<p>This is where companies like <a href="https://en.wikipedia.org/wiki/Markmonitor">Markmonitor</a> come into the picture. Their services include:</p>

<blockquote>
  <p>software intended to protect corporate brands from Internet counterfeiting, fraud, piracy, and cybersquatting</p>
</blockquote>

<p>Markmonitor has an impressive clientele involving the likes of companies such as Amazon, Google, Akamai, Alibaba, Baidu etc!</p>

<p>Essentially, think of Markmonitor as a service that reminds you to pay for your domain names before they expire so that you aren’t bullied into someone on the interwebs squatting your domain name.
This is quite amusing to me as an individual but it is a sensible service nonetheless that benefits corporations.</p>

<p>I still find it quite hard to wrap my head around this. :)</p>

<h4 id="appendix">Appendix</h4>

<h5 id="amazoncom">amazon.com</h5>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># whois.markmonitor.com

Domain Name: amazon.com
Registry Domain ID: 281209_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.markmonitor.com
Registrar URL: http://www.markmonitor.com
Updated Date: 2023-05-16T18:56:31+0000
Creation Date: 1994-11-01T05:00:00+0000
Registrar Registration Expiration Date: 2024-10-30T07:00:00+0000
Registrar: MarkMonitor, Inc.
</code></pre></div></div>

<h5 id="akamaicom">akamai.com</h5>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># whois.markmonitor.com

Domain Name: akamai.com
Registry Domain ID: 2906556_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.markmonitor.com
Registrar URL: http://www.markmonitor.com
Updated Date: 2022-04-11T18:10:46+0000
Creation Date: 1998-08-17T04:00:00+0000
Registrar Registration Expiration Date: 2024-08-16T04:00:00+0000
Registrar: MarkMonitor, Inc.
</code></pre></div></div>

<h5 id="googlecom">google.com</h5>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># whois.markmonitor.com

Domain Name: google.com
Registry Domain ID: 2138514_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.markmonitor.com
Registrar URL: http://www.markmonitor.com
Updated Date: 2019-09-09T15:39:04+0000
Creation Date: 1997-09-15T07:00:00+0000
Registrar Registration Expiration Date: 2028-09-13T07:00:00+0000
Registrar: MarkMonitor, Inc.
</code></pre></div></div>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[Most of us register and renew our domain names through various registrars such as Namecheap, Godaddy, the late Google domains etc. But how do the fortune 500 companies do it? I am glad you asked!]]></summary></entry><entry><title type="html">`tar` is fun?</title><link href="https://blog.sayan.page/tar-is-fun/" rel="alternate" type="text/html" title="`tar` is fun?" /><published>2023-12-24T00:00:00+00:00</published><updated>2023-12-24T00:00:00+00:00</updated><id>https://blog.sayan.page/tar-is-fun</id><content type="html" xml:base="https://blog.sayan.page/tar-is-fun/"><![CDATA[<p>Have you ever wondered why the unix command <code class="language-plaintext highlighter-rouge">tar</code> is a cryptic mess and everytime you need to use it you need to head back to the man page to look them up?
Well fear no more – you could just remember these mnemonic flags instead and make your life easier!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ file archive.tar.gz
archive.tar.gz: gzip compressed data, last modified: Sun Dec 24 13:42:15 2023, from Unix, original size modulo 2^32 1372672
</code></pre></div></div>

<h2 id="list-contents-of-an-archive">list contents of an archive</h2>

<p>Use <code class="language-plaintext highlighter-rouge">wtf</code>: what the fuck is in that archive?</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">tar </span>wtf archive.tar.gz
- 8&lt;-
</code></pre></div></div>

<h2 id="extract-the-archive">extract the archive</h2>

<p>Use <code class="language-plaintext highlighter-rouge">pfx</code>: please fucking extract the archive!</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">tar </span>pfx archive.tar.gz
- 8&lt;-
</code></pre></div></div>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[Have you ever wondered why the unix command tar is a cryptic mess and everytime you need to use it you need to head back to the man page to look them up? Well fear no more – you could just remember these mnemonic flags instead and make your life easier!]]></summary></entry><entry><title type="html">Netflix: Stats for Nerds</title><link href="https://blog.sayan.page/netflix-debug-mode/" rel="alternate" type="text/html" title="Netflix: Stats for Nerds" /><published>2022-07-11T00:00:00+01:00</published><updated>2022-07-11T00:00:00+01:00</updated><id>https://blog.sayan.page/netflix-debug-mode</id><content type="html" xml:base="https://blog.sayan.page/netflix-debug-mode/"><![CDATA[<p>Netflix on desktop has a hidden debug menu. The key combinations to trigger it are</p>

<p>MacOS: <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Option</kbd> + <kbd>Q</kbd></p>

<p>Windows: <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>Q</kbd></p>

<p>This will bring up an overlay dialog with wide range of statistics and debugging information.</p>

<p><strong>Note</strong>: This shortcut does not work when you are in fullscreen mode.</p>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[Netflix on desktop has a hidden debug menu. The key combinations to trigger it are]]></summary></entry><entry><title type="html">TIL: Recondite Python</title><link href="https://blog.sayan.page/til-recondite-python/" rel="alternate" type="text/html" title="TIL: Recondite Python" /><published>2022-07-01T00:00:00+01:00</published><updated>2022-07-01T00:00:00+01:00</updated><id>https://blog.sayan.page/til-recondite-python</id><content type="html" xml:base="https://blog.sayan.page/til-recondite-python/"><![CDATA[<p>This page is a collection of obscure facts about the Python programming language.</p>

<h2 class="no_toc" id="table-of-contents">Table of Contents</h2>

<ul id="markdown-toc">
  <li><a href="#the-__debug__-constant" id="markdown-toc-the-__debug__-constant">the <code class="language-plaintext highlighter-rouge">__debug__</code> constant</a>    <ul>
      <li><a href="#__debug__-in-repl-shell" id="markdown-toc-__debug__-in-repl-shell"><code class="language-plaintext highlighter-rouge">__debug__</code> in REPL shell</a></li>
      <li><a href="#__debug__-in-scripts" id="markdown-toc-__debug__-in-scripts"><code class="language-plaintext highlighter-rouge">__debug__</code> in scripts</a></li>
    </ul>
  </li>
</ul>

<h2 id="the-__debug__-constant">the <code class="language-plaintext highlighter-rouge">__debug__</code> constant</h2>

<p>Python has a <a href="https://docs.python.org/3/library/constants.html#debug__" target="_blank">built-in boolean constant</a>
named <code class="language-plaintext highlighter-rouge">__debug__</code>.</p>

<p>It is set to <code class="language-plaintext highlighter-rouge">True</code> whenever you run a REPL shell or call a script with the
<code class="language-plaintext highlighter-rouge">python script.py</code> i.e. by default.</p>

<p>It is set to <code class="language-plaintext highlighter-rouge">False</code> only when you pass the <code class="language-plaintext highlighter-rouge">-O</code> or the <code class="language-plaintext highlighter-rouge">-OO</code> flags to the python executable.</p>

<p>These flags are described in the Python manual page as:</p>

<p><code class="language-plaintext highlighter-rouge">-O</code> Remove assert statements and any code conditional on the value of <strong>debug</strong>;
augment the filename for compiled (bytecode) files by adding .opt-1 before the .pyc
extension.</p>

<p><code class="language-plaintext highlighter-rouge">-OO</code> Do <code class="language-plaintext highlighter-rouge">-O</code> and also discard docstrings; change the filename for compiled
(bytecode) files by adding .opt-2 before the .pyc extension.</p>

<h3 id="__debug__-in-repl-shell"><code class="language-plaintext highlighter-rouge">__debug__</code> in REPL shell</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3
Python 3.9.13 <span class="o">(</span>main, May 24 2022, 21:28:31<span class="o">)</span>
<span class="o">[</span>Clang 13.1.6 <span class="o">(</span>clang-1316.0.21.2<span class="o">)]</span> on darwin
Type <span class="s2">"help"</span>, <span class="s2">"copyright"</span>, <span class="s2">"credits"</span> or <span class="s2">"license"</span> <span class="k">for </span>more information.
<span class="o">&gt;&gt;&gt;</span> __debug__
True

</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 <span class="nt">-O</span>
Python 3.9.13 <span class="o">(</span>main, May 24 2022, 21:28:31<span class="o">)</span>
<span class="o">[</span>Clang 13.1.6 <span class="o">(</span>clang-1316.0.21.2<span class="o">)]</span> on darwin
Type <span class="s2">"help"</span>, <span class="s2">"copyright"</span>, <span class="s2">"credits"</span> or <span class="s2">"license"</span> <span class="k">for </span>more information.
<span class="o">&gt;&gt;&gt;</span> __debug__
False

</code></pre></div></div>

<h3 id="__debug__-in-scripts"><code class="language-plaintext highlighter-rouge">__debug__</code> in scripts</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cat </span>script.py
print<span class="o">(</span>__debug__<span class="o">)</span>

<span class="nv">$ </span>python3 script.py
True
<span class="nv">$ </span>python3 <span class="nt">-O</span> script.py
False
<span class="nv">$ </span>python3 <span class="nt">-OO</span> script.py
False
</code></pre></div></div>]]></content><author><name>Sayan Goswami</name></author><summary type="html"><![CDATA[This page is a collection of obscure facts about the Python programming language.]]></summary></entry></feed>