<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>Alireza M. Kamelabad — Work</title><subtitle>What I can do for a team — experience, skills, shipped projects, and notes on the craft of research engineering.</subtitle><id>https://ali.mk/work/atom.xml</id><link rel="alternate" type="text/html" href="https://ali.mk/work/" /><link rel="self" type="application/atom+xml" href="https://ali.mk/work/atom.xml" /><updated>2026-07-14T00:00:00.000Z</updated><author><name>Alireza M. Kamelabad</name></author><entry><title>The (rotten) Apple Illusion</title><id>https://ali.mk/posts/2026-07-14-the-rotten-apple-illusion/</id><link href="https://ali.mk/posts/2026-07-14-the-rotten-apple-illusion/" /><published>2026-07-14T00:00:00.000Z</published><updated>2026-07-14T00:00:00.000Z</updated><summary>How the EU Standoff Exposed a Walled Garden of Disrespect</summary><category term="Apple" /><category term="DMA" /><category term="European Union (EU)" /><content type="html"><![CDATA[<p>As a tech enthusiast, I’ve always believed in experimenting with different ecosystems to find the best tools for my daily life and workflow. Up until early 2025, I was fully immersed in the Samsung ecosystem. My Galaxy S22 Plus, Galaxy Tab S8 Plus, and Buds Pro worked flawlessly together. They were cutting-edge, unrestricted, and constantly evolving with new AI integrations.</p>
<p>But I wanted to experience the legendary “Apple magic.” I wanted to see what the absolute pinnacle of their hardware and software integration felt like.</p>
<p>So, in March 2025, I made a massive financial commitment. I went all-in, purchasing the iPhone 16 Pro, an iPad Pro M4, AirPods Pro 2nd Gen, an Apple TV, AirTags, and an Apple Pencil Pro. These flagship devices were significantly more expensive than my Samsung setup, but I was buying into a promise: seamless integration, premium performance, and the highly anticipated “Apple Intelligence” they had promised would revolutionize their platforms.<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup></p>
<p>It didn’t take long for the buyer’s remorse to set in.</p>
<hr>
<h2 id="a-timeline-of-broken-promises">A Timeline of Broken Promises</h2>
<p>The initial failure was Apple’s inability to deliver Apple Intelligence on time. When iOS 18 rolled out, instead of stepping into the future, I felt like I had been thrown four years back in time. The capabilities of my brand-new, premium iPhone 16 Pro were fundamentally lagging behind what my older Samsung S22 Plus was doing before Gemini even became a standard feature.</p>
<p>Then came the iOS 26 cycle. Apple heavily marketed a suite of new features, but as a user living in the European Union, I quickly realized the fine print: the best features were either locked to US English or completely geoblocked in the EU. Features as simple as iPhone Mirroring were stripped from my multi-thousand-euro devices.<sup><a href="#user-content-fn-2" id="user-content-fnref-2" data-footnote-ref="" aria-describedby="footnote-label">2</a></sup></p>
<p>But today was the breaking point.</p>
<p>I recently updated to the iOS 27 beta, eager to finally experience the revamped Siri interface and the next-generation AI features Apple has been showcasing. After installing the update, I searched everywhere. Nothing. The new Siri experience was completely missing.</p>
<p>After digging through Apple’s official statements and reading through frustrating Reddit threads, the reality hit me: Apple has intentionally blocked the new Siri AI in the EU.<sup><a href="#user-content-fn-3" id="user-content-fnref-3" data-footnote-ref="" aria-describedby="footnote-label">3</a></sup></p>
<p>Their justification? The European Union’s Digital Markets Act (DMA).<sup><a href="#user-content-fn-4" id="user-content-fnref-4" data-footnote-ref="" aria-describedby="footnote-label">4</a></sup></p>
<hr>
<h2 id="the-regulatory-standoff-privacy-as-a-weapon">The Regulatory Standoff: Privacy as a Weapon</h2>
<p>Under the DMA, gatekeeper companies like Apple are required to allow interoperability. If Apple gives its own AI (Siri) deep, system-level hooks into iOS to read context, messages, and screen data, the EU dictates they must offer a secure way for third-party assistants to have that same access.</p>
<p>In June 2026, Apple proposed a “Trusted System Agent” to act as a middleman for this data, which the European Commission rejected.<sup><a href="#user-content-fn-5" id="user-content-fnref-5" data-footnote-ref="" aria-describedby="footnote-label">5</a></sup> Following a major court loss on July 8, 2026, where Europe’s General Court upheld the DMA’s strict gatekeeper rules against Apple’s appeals,<sup><a href="#user-content-fn-6" id="user-content-fnref-6" data-footnote-ref="" aria-describedby="footnote-label">6</a></sup> Apple threw its hands up. Instead of complying, they took their ball and went home, indefinitely blocking the new Siri AI for the entire European market.</p>
<p>Apple’s public defense is entirely predictable: <em>Privacy and Security</em>. They claim that granting third-party AIs the deep system access required by the DMA is fundamentally dangerous, arguing that it is impossible to mitigate the risks of bad actors scraping user data.</p>
<p>But when you actually scrutinize this argument, it completely falls apart under basic technical and logical analysis.</p>
<h4 id="1-the-solvable-engineering-problem-the-waterfall-proxy-solution">1. The Solvable Engineering Problem (The Waterfall Proxy Solution)</h4>
<p>Apple’s claim that it is “impossible” to safely comply with the interoperability rules is an insult to their users’ intelligence. As anyone with a background in software web development knows, secure data isolation and intermediary routing are highly solvable problems.</p>
<p>Instead of allowing third-party AI systems direct, unfettered access to core system hooks, Apple could easily engineer a <strong>waterfall proxy architecture</strong> at the OS level. This middle layer would sequentially intercept, authenticate, and safely sandbox third-party AI requests before routing them to system apps. It would act as a secure buffer, ensuring external assistants never directly touch raw underlying data. Apple has the best software engineering talent in the world; they didn’t fail to build this because it was a technical impossibility. They failed because they chose to spend their resources paying lawyers to fight the EU in court, hoping to protect their monopoly.</p>
<h4 id="2-the-patronizing-consent-argument">2. The Patronizing “Consent” Argument</h4>
<p>Apple’s stance relies on the idea that users are fundamentally incapable of managing their own risks. In modern software, we already use a robust “inform and opt-in” model. iOS asks us explicitly if we want to grant an app access to our camera, our location, or our microphone.</p>
<p>If Apple genuinely cared about user choice, they could implement a clear, highly specific warning screen:</p>
<blockquote>
<p><em>“Warning: Granting this third-party AI system access allows it to process your screen and personal data. Proceed at your own risk.”</em></p>
</blockquote>
<p>Let the user decide. Instead, Apple’s logic is patronizing: <em>We don’t trust you to make the right choice with your own hardware, so we are stripping the feature entirely.</em></p>
<h4 id="3-the-macos-hypocrisy">3. The macOS Hypocrisy</h4>
<p>The most glaring hole in Apple’s defense is macOS. On a Mac, you can download whatever third-party software you want from the open web, grant it deep accessibility permissions to read your screen, and Apple trusts you to manage it. macOS is currently exempt from the DMA’s strictest mobile gatekeeper rules, so Apple allows this freedom there.<sup><a href="#user-content-fn-7" id="user-content-fnref-7" data-footnote-ref="" aria-describedby="footnote-label">7</a></sup> The “unmitigated danger” they claim exists on iOS mysteriously vanishes when it comes to their desktop operating system.</p>
<hr>
<h2 id="double-gatekeeping-software-blocks-and-hardware-taxes">Double Gatekeeping: Software Blocks and Hardware Taxes</h2>
<p>To make matters worse, Apple is running a double-gatekeeping scheme. Even if you live outside the EU and can access these features, Apple has weaponized software updates to force a hardware super-cycle.</p>
<p>While the baseline requirement for Apple Intelligence started at the iPhone 15 Pro, running the localized, advanced voice models introduced for iOS 27 now requires devices with at least 12GB of RAM<sup><a href="#user-content-fn-8" id="user-content-fnref-8" data-footnote-ref="" aria-describedby="footnote-label">8</a></sup>—conveniently locking out users who bought flagships just a year or two ago. They are squeezing users on hardware requirements while simultaneously cutting off software access for an entire continent.</p>
<p>Meanwhile, competitors like Google and Samsung actually chose to respect their users. They adapted to the EU’s regulations, pushed Gemini and Galaxy AI to their European customers, and even backported advanced features to older hardware like the S22 series.<sup><a href="#user-content-fn-9" id="user-content-fnref-9" data-footnote-ref="" aria-describedby="footnote-label">9</a></sup> They played by the rules and delivered the technology.</p>
<hr>
<h2 id="prediction-the-long-walk-to-2027">Prediction: The Long Walk to 2027</h2>
<p>Where does this leave us? Right now, Apple is playing a corporate game of chicken, using millions of European users as leverage to pressure regulators. But Europe is too massive a market for Apple to permanently offer a degraded, second-rate product.</p>
<p>My prediction is that Apple will eventually be forced to cave, but it won’t be quick. They will likely spend the rest of 2026 licking their wounds from their recent court defeat. Only then will they quietly begin engineering the secure proxy APIs they should have built in the first place. We likely won’t see the new Siri experience unlocked in the EU until a major point-update like iOS 27.5, or alongside iOS 28 in <strong>mid-to-late 2027</strong>.</p>
<hr>
<h2 id="time-to-exit-the-walled-garden">Time to Exit the Walled Garden</h2>
<p>This entire saga is a masterclass in corporate disrespect. I paid an incredible premium to enter this ecosystem, expecting a company that delivers on its promises. Instead, I was handed an artificially crippled device, caught in the crossfire of a political standoff that Apple manufactured by refusing to innovate within the law.</p>
<p>As a tech enthusiast who just wanted to experience their take on the future of computing, they have devastatingly failed me. I refuse to hold onto devices that treat me like a second-class consumer while a four-year-old Samsung phone handles modern AI workflows with ease.</p>
<p>I am officially done waiting. It is time to offload my Apple devices on the secondary market, liquidate the Apple stock in my portfolio, and return to an ecosystem that actually functions, respects its users, and innovates without holding its customers hostage.</p>
<hr>
<section data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-1">
<p><a href="https://www.apple.com/newsroom/2024/06/apple-introduces-apple-intelligence-for-iphone-ipad-and-mac/">Apple introduces Apple Intelligence</a> (Apple Newsroom, WWDC 2024 announcement). <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-2">
<p><a href="https://www.cnbc.com/2024/06/21/apple-says-it-wont-roll-out-ai-features-in-europe-due-to-regulatory-concerns.html">Apple says it won’t roll out AI features in Europe due to regulatory concerns</a> (CNBC, June 21, 2024 — details the initial EU delay of Apple Intelligence, iPhone Mirroring, and SharePlay). <a href="#user-content-fnref-2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-3">
<p><a href="https://www.apple.com/newsroom/2026/06/due-to-dma-siri-ai-delayed-in-eu-for-ios-27-and-ipados-27/">Due to DMA, Siri AI delayed in EU for iOS 27 and iPadOS 27</a> (Apple Newsroom, June 8, 2026 — Apple’s own statement confirming Siri AI ships on macOS 27 and visionOS 27 but not iOS 27, iPadOS 27, or watchOS 27 in the EU). <a href="#user-content-fnref-3" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-4">
<p><a href="https://commission.europa.eu/strategy-and-policy/priorities-2019-2024/europe-fit-digital-age/digital-markets-act-ensuring-fair-and-open-digital-markets_en">The Digital Markets Act: ensuring fair and open digital markets</a> (European Commission official overview). <a href="#user-content-fnref-4" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-5">
<p><a href="https://www.macrumors.com/2026/06/09/eu-says-decision-not-to-launch-siri-ai-in-europe-is-apples/">EU Says Decision Not to Launch Siri AI in Europe Is Apple’s Alone</a> (MacRumors, June 9, 2026 — reports that the Commission says Apple never submitted a concrete Trusted System Agent proposal and instead sought a blanket exemption from its interoperability obligations, which the Commission does not offer). <a href="#user-content-fnref-5" data-footnote-backref="" aria-label="Back to reference 5" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-6">
<p><a href="https://www.macrumors.com/2026/07/08/apple-loses-eu-fight-app-store-gatekeeper-label/">Apple Loses EU Fight Over App Store Gatekeeper Label</a> (MacRumors, July 8, 2026); see also the <a href="https://curia.europa.eu/site/upload/docs/application/pdf/2026-07/cp260096en.pdf">General Court’s official press release</a> (Court of Justice of the European Union, July 2026), confirming the General Court dismissed Apple’s challenge to its gatekeeper designation for the App Store and iOS. <a href="#user-content-fnref-6" data-footnote-backref="" aria-label="Back to reference 6" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-7">
<p><a href="https://dataconomy.com/2026/07/09/eu-court-rejects-apple-digital-markets-act-gatekeeper-tag/">Apple loses EU court fight over App Store ‘gatekeeper’ status</a> (Dataconomy, July 9, 2026 — notes macOS has not been designated a core platform service under the DMA, unlike iOS); corroborated by Apple’s own <a href="https://www.apple.com/newsroom/2026/06/due-to-dma-siri-ai-delayed-in-eu-for-ios-27-and-ipados-27/">June 2026 statement</a> that Siri AI shipped on macOS 27 in the EU while withheld from iOS 27 and iPadOS 27. <a href="#user-content-fnref-7" data-footnote-backref="" aria-label="Back to reference 7" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-8">
<p><a href="https://www.macrumors.com/2026/06/08/most-powerful-on-device-ai-now-requires-iphone-17-pro-or-air/">Apple’s Most Powerful On-Device AI Now Requires iPhone 17 Pro or iPhone Air</a> (MacRumors, June 8, 2026 — the most advanced on-device model in iOS 27 requires 12GB of unified memory, up from the previous 8GB Apple Intelligence baseline, excluding devices like the base iPhone 17). <a href="#user-content-fnref-8" data-footnote-backref="" aria-label="Back to reference 8" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-9">
<p><a href="https://news.samsung.com/global/samsung-brings-galaxy-ai-to-more-galaxy-devices">Samsung brings Galaxy AI to more Galaxy devices</a> (Samsung Newsroom — officially backporting AI features to the Galaxy S22 series). <a href="#user-content-fnref-9" data-footnote-backref="" aria-label="Back to reference 9" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content></entry><entry><title>Break Free from Zotero Storage Limits: How to Host Your Own WebDAV Server</title><id>https://ali.mk/posts/2026-07-08-break-free-from-zotero-storage-limits-how-to-host-your-own-webdav-server/</id><link href="https://ali.mk/posts/2026-07-08-break-free-from-zotero-storage-limits-how-to-host-your-own-webdav-server/" /><published>2026-07-08T00:00:00.000Z</published><updated>2026-07-08T00:00:00.000Z</updated><summary>Stop suffering the 300MB of Zotero -- Start storing the PDFs!</summary><category term="zotero" /><category term="reference manager" /><category term="WebDAV" /><category term="storage" /><content type="html"><![CDATA[<p>As a researcher, academic, or just someone who reads a lot of papers, you either already have a reference management software of your choice or you are just suffering (choose it; and choose Zotero!!)! If you already know what a reference manager is, then most likely it is Zotero that you are already using; <strong>an absolute lifesaver</strong>. With the recent release of Zotero 9, the reading and annotating experience has reached a whole new level with a great new UI and UX that I am personally enjoying much. Being able to highlight, take notes directly on PDFs, and seamlessly extract those annotations into your word processor makes it unparalleled in the reference management space. Also, there are many efforts in developing further MCP around zotero and connecting it to the AI assistants of your choice.</p>
<p>But there is one major catch.</p>
<p>As soon as you start aggressively saving webpages, full-text PDFs, and supplementary materials, you’ll hit a wall: <strong>Zotero’s free cloud storage is capped at 300 MB.</strong> That is enough for thousands of paper meta-data but not paper pdfs.</p>
<p>I was in agony for many years selecting and deleting pdfs of older papers (and I do not know why I didn’t do anything about it until now!). But I eventually solved it! and I recommend you to do so too. Especially before piling up your library. If you want your entire library (PDFs, highlights, and notes) synced to the cloud so you can read on your iPad/tablet on the train and then seamlessly switch back to your desktop, you need more space. Zotero offers paid storage plans, which are great and support the project. However, if you have a massive library, those costs can add up.</p>
<p>Fortunately, Zotero gives you another option for syncing your attachment files: <strong>WebDAV</strong>.</p>
<p>In this post, I’ll explain what WebDAV is and give you a comprehensive, step-by-step guide (that I did myself) on how to set up your own secure WebDAV server on an Ubuntu VPS to get practically unlimited storage for your Zotero library.</p>
<h2 id="what-is-webdav">What is WebDAV?</h2>
<p>WebDAV (Web Distributed Authoring and Versioning) is an extension of the standard HTTP protocol. Instead of just letting you <em>view</em> files on a web server, WebDAV allows you to create, edit, move, and upload files remotely.</p>
<p>Think of it like turning a web server into a network drive.</p>
<p>When you use WebDAV with Zotero, a clever division of labor happens:</p>
<ol>
<li><strong>Metadata &#x26; Notes:</strong> Your library data (the citations, tags, and text notes) continues to sync seamlessly via Zotero’s free native sync servers (which do not count toward your file storage quota).</li>
<li><strong>Attachments:</strong> Your heavy files (PDFs, EPUBs, snapshots) are synced directly to your personal WebDAV server.</li>
</ol>
<p><em>Note: If you don’t want to tinker with Linux servers, Zotero supports out-of-the-box integration with several 3rd-party cloud providers that offer WebDAV (like <a href="https://koofr.eu/blog/posts/koofr-with-zotero-via-webdav">Koofr [I use this one]</a> or Nextcloud). You can read more about these alternatives in the <a href="https://www.zotero.org/support/kb/webdav_services" title="null">official Zotero documentation for WebDAV providers</a>.</em></p>
<p>But if you already have a Virtual Private Server (VPS) or love self-hosting, setting up your own WebDAV server is incredibly rewarding. Let’s build it.</p>
<h2 id="the-ultimate-ubuntu-vps-setup-for-zotero-webdav">The Ultimate Ubuntu VPS Setup for Zotero WebDAV</h2>
<p>We’re going to start from a fresh Ubuntu server (as I did). We will secure it, install <a href="https://nginx.org/">Nginx</a> and <a href="http://www.webdav.org/">WebDAV</a>, configure SSL for encryption, and hook it up to Zotero.</p>
<p><strong>Prerequisites:</strong></p>
<ul>
<li>A VPS running Ubuntu (22.04 or later ---it would probably work with older versions too. But I personally just tried it with 26.04).</li>
<li>A domain or subdomain pointed to your server’s IP address (e.g., <code>zotero.yourdomain.com</code>).</li>
</ul>
<h3 id="step-1-secure-your-server">Step 1: Secure Your Server</h3>
<p>Never leave a fresh VPS exposed with default root passwords. Let’s create a new user, set up SSH keys, and disable password logins.</p>
<p>Log into your server as <code>root</code> and create a new user (I’ll use <code>ali</code>, but you can use your name):</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo adduser ali</span></span>
<span class="line"><span>sudo usermod -aG sudo ali</span></span></code></pre>
<p>Switch to your new user to set up your SSH keys:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo su - ali</span></span>
<span class="line"><span>mkdir -p ~/.ssh &#x26;&#x26; chmod 700 ~/.ssh</span></span></code></pre>
<p>Add your local computer’s public SSH key (<code>~/.ssh/id_ed25519.pub</code> or <code>~/.ssh/id_rsa.pub</code>) to the server:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>echo "YOUR_PUBLIC_KEY_HERE" >> ~/.ssh/authorized_keys</span></span>
<span class="line"><span>chmod 600 ~/.ssh/authorized_keys</span></span>
<span class="line"><span>exit</span></span>
<span class="line"><span></span></span></code></pre>
<p>Now, back as <code>root</code>, lock down SSH. We need to disable root login and password authentication:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span># Temporarily fix terminal issues if using a modern terminal emulator like Ghostty</span></span>
<span class="line"><span>TERM=xterm-256color sudo nano /etc/ssh/sshd_config</span></span>
<span class="line"><span></span></span></code></pre>
<p>Find and ensure these lines are set:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>PermitRootLogin no</span></span>
<span class="line"><span>PasswordAuthentication no</span></span>
<span class="line"><span>PubkeyAuthentication yes</span></span></code></pre>
<p><strong>Ubuntu 22.04+ Pro-Tip:</strong> Ubuntu often includes an override file for cloud setups. If you still get prompted for a password after the step above, edit this file too:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>TERM=xterm-256color sudo nano /etc/ssh/sshd_config.d/50-cloud-init.conf</span></span></code></pre>
<p>Change <code>PasswordAuthentication yes</code> to <code>no</code>.</p>
<p>Restart SSH and set up the UFW Firewall:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo systemctl restart ssh</span></span>
<span class="line"><span>sudo ufw allow ssh</span></span>
<span class="line"><span>sudo ufw allow 'Nginx Full'</span></span>
<span class="line"><span>sudo ufw enable</span></span></code></pre>
<p>Test your SSH connection in a <em>new</em> terminal window before closing your root session. If you can log in without a password, you’re good to go!</p>
<h3 id="step-2-install-nginx-and-webdav">Step 2: Install Nginx and WebDAV</h3>
<p>Log in as your standard user (<code>ali</code>). We need a web server (Nginx) and the WebDAV extensions:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo apt update &#x26;&#x26; sudo apt install -y nginx nginx-extras</span></span></code></pre>
<p>Next, install Let’s Encrypt Certbot so we can secure our PDFs in transit:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo apt install -y certbot python3-certbot-nginx</span></span></code></pre>
<h3 id="step-3-create-the-zotero-directory">Step 3: Create the Zotero Directory</h3>
<p>Here is a specific quirk about Zotero: when you give it a WebDAV URL, <strong>it explicitly looks for a directory named</strong> <code>zotero</code> <strong>inside that location</strong>.</p>
<p>Let’s create the root directory, and the nested <code>zotero</code> directory it expects:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo mkdir -p /var/www/zotero/zotero</span></span>
<span class="line"><span>sudo chown -R www-data:www-data /var/www/zotero</span></span>
<span class="line"><span>sudo chmod -R 755 /var/www/zotero</span></span></code></pre>
<h3 id="step-4-set-up-authentication">Step 4: Set Up Authentication</h3>
<p>You don’t want anyone on the internet accessing your PDFs. We will secure the server with Basic HTTP Authentication.</p>
<p>Install the required utilities:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo apt install -y apache2-utils</span></span></code></pre>
<p>Generate a password file. Replace <code>zoterouser</code> with whatever username you want to type into your Zotero app (this has nothing to do with your system username):</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo htpasswd -c /etc/nginx/.htpasswd zoterouser</span></span></code></pre>
<p>You will be prompted to create a strong password. Note this down; you’ll need it later.</p>
<h3 id="step-5-configure-nginx">Step 5: Configure Nginx</h3>
<p>Now we tell Nginx how to handle the WebDAV requests. Create a new site configuration:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo nano /etc/nginx/sites-available/zotero</span></span></code></pre>
<p>Paste the following configuration (replace <code>zotero.yourdomain.com</code> with your actual subdomain):</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>server {</span></span>
<span class="line"><span>    listen 80;</span></span>
<span class="line"><span>    server_name zotero.yourdomain.com;</span></span>
<span class="line"><span></span></span>
<span class="line"><span>    root /var/www/zotero;</span></span>
<span class="line"><span></span></span>
<span class="line"><span>    auth_basic "Zotero WebDAV";</span></span>
<span class="line"><span>    auth_basic_user_file /etc/nginx/.htpasswd;</span></span>
<span class="line"><span></span></span>
<span class="line"><span>    client_max_body_size 100M;</span></span>
<span class="line"><span>    autoindex on;</span></span>
<span class="line"><span></span></span>
<span class="line"><span>    location / {</span></span>
<span class="line"><span>        dav_methods PUT DELETE MKCOL COPY MOVE;</span></span>
<span class="line"><span>        dav_ext_methods PROPFIND OPTIONS;</span></span>
<span class="line"><span>        dav_access user:rw group:r all:r;</span></span>
<span class="line"><span>        create_full_put_path on;</span></span>
<span class="line"><span>    }</span></span>
<span class="line"><span>}</span></span></code></pre>
<p><em>Note: Avoid using</em> <code>try_files</code> <em>in this location block. Doing so will block the</em> <code>PUT</code> <em>requests Zotero uses to verify the server, resulting in a 404 error during setup!</em></p>
<p>Enable the site and verify the Nginx syntax:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo ln -s /etc/nginx/sites-available/zotero /etc/nginx/sites-enabled/</span></span>
<span class="line"><span>sudo nginx -t</span></span>
<span class="line"><span>sudo systemctl reload nginx</span></span></code></pre>
<h3 id="step-6-secure-with-ssl-https">Step 6: Secure with SSL (HTTPS)</h3>
<p>Run Certbot to automatically fetch an SSL certificate and update your Nginx configuration to use HTTPS:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>sudo certbot --nginx -d zotero.yourdomain.com</span></span></code></pre>
<p>Follow the prompts. Certbot will automatically alter your Nginx file to route traffic securely over port 443.</p>
<p>To verify WebDAV is actually responding to requests, you can run this curl command from your terminal:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>curl -u zoterouser -X PROPFIND https://zotero.yourdomain.com/zotero/</span></span></code></pre>
<p>If you enter your password and see a block of XML code in the terminal, congratulations! Your WebDAV server is alive.</p>
<h3 id="step-7-connect-the-zotero-app">Step 7: Connect the Zotero App</h3>
<p>The hard part is over. Now, let’s point Zotero to your new server:</p>
<ol>
<li>Open Zotero on your computer.</li>
<li>Go to <strong>Edit</strong> > <strong>Settings</strong> (or <strong>Zotero</strong> > <strong>Preferences</strong> on Mac) > <strong>Sync</strong>.</li>
<li>Under the <strong>File Syncing</strong> section, check <strong>“Sync attachment files in My Library using WebDAV”</strong>.</li>
<li>Enter your details:</li>
</ol>
<ul>
<li><strong>URL:</strong> <code>https://zotero.yourdomain.com/zotero/</code></li>
<li><strong>Username:</strong> The username you created in step 4 (<code>zoterouser</code>).</li>
<li><strong>Password:</strong> The password you generated in step 4.</li>
</ul>
<ol start="5">
<li>Click <strong>“Verify Server”</strong>.</li>
</ol>
<p>Zotero will reach out to your VPS, create a test file, and read it back. You should see a green checkmark and the message: <strong>“File sync is successfully set up!”</strong></p>
<h3 id="conclusion">Conclusion</h3>
<p>You now have a fully private, fully secure storage backend for your entire research library. Every time you drag a PDF into Zotero, it will quietly upload to your VPS. You can connect your laptop, your desktop, and your iPad to the same WebDAV URL and keep your entire workflow perfectly synchronized without ever worrying about hitting a 300 MB quota again.</p>
<p>Happy researching!</p>]]></content></entry><entry><title>Three Doors: Announcing the New Site</title><id>https://ali.mk/posts/announcing-the-new-site/</id><link href="https://ali.mk/posts/announcing-the-new-site/" /><published>2026-07-07T00:00:00.000Z</published><updated>2026-07-07T00:00:00.000Z</updated><summary>Why ali.mk is now a house with three doors instead of one crowded room.</summary><category term="design" /><category term="meta" /><category term="personal site" /><category term="astro" /><content type="html"><![CDATA[<p>I started the journey of having a personal web footprint with my first website <code>horotat.com</code>. That is right after the time that I passed the course <strong>Web Design</strong> during my bachelor’s. I started from wordpress, the moved to pure <code>HTML</code>, and adding <code>CSS</code> to it later on. I have always wanted an effective, personal, and customized digital presence. But for many years, I was very confused as in, what do I really want from my personal website. Since for now, I am in academia, this was a perfect opportunity for me to establish a real base for presenting myself properly in the scientific society. That is when I discovered <code>Jekyll</code> around 2018. I moved to <code>Jekyll</code> using <em>GitHub Pages</em> to deploy my static, fast website. After exploring much, I endded up with the amazing <a href="https://chirpy.cotes.page/posts/getting-started/">Chirpy</a> theme. It has a great active commmunity around it who are taking it forward to date, and make it even better.</p>
<p>In the meantime, I figured out the north macedonian domain of <code>.mk</code> which was the exact initials of my last name (<strong>M</strong>ahmoudi <strong>K</strong>amelabad) and I noticed that my short and long first names (ali and alireza) are both available for this domain so I quickly grabbed them and I love them very much. I must say, I have never seen a better personal website domain than mine! So I became: <a href="https://ali.mk">ali.mk and alireza.mk</a>.</p>
<p>As I grew and did my career and personality, I felt that I need more than one dimension to present online, each of which have their own audience; yet, the information of each would mostly be noise for the other ones---a recruiter scrolling past political essays to find my CV, a fellow researcher wading through film reviews to find a publication, a friend getting a wall of BibTeX before the actual writing. Everyone got the whole of me, whether they’d asked for it or not. It worked, technically. It never quite felt right. That is where the idea of the three door came from.</p>
<p>The people I needed to talk to are:</p>
<ol>
<li><strong>Professionals Hiring</strong>: who would want to quickly get to know about my skills, passion, and match for their workflow and business.</li>
<li><strong>Academics</strong>: the fellow researchers and scientists who can access my papers, resources, and contributions to science.</li>
<li><strong>Readers and Followers</strong>: a place where I could publish my non-academic writings, whether political, opinion, diary, etc.</li>
</ol>
<p>The new site fixes that by not trying to be one thing. The root page is a <strong>threshold</strong> — you pick a door, and each door opens onto a self-contained room that never cross-surfaces the others’ content:</p>
<ul>
<li><strong><a href="/research/">/research</a></strong> — publications, field notes, the academic CV. For fellow researchers.</li>
<li><strong><a href="/work/">/work</a></strong> — experience, toolbox, craft notes, the availability line. For people hiring.</li>
<li><strong><a href="/life/">/life</a></strong> — essays (politics and opinion included), the shelf of films and shows, the running/hiking log, the parts of me that don’t belong on a CV.</li>
</ul>
<p>Nothing is hidden — everything is still public and indexed — the separation is about <em>surfacing</em>, not secrecy. A recruiter reading Work is simply never pitched an essay about closing my Twitter account; a reader in Life is never handed a CV. The only threads back are the wordmark, which always returns to the threshold, and a quiet footer line: “elsewhere in the house.”</p>
<h3 id="the-design-language">The design language</h3>
<p>Once the three-room idea was settled, the visual language had to do two contradictory things: read as one coherent person, and let each room have its own temperament. The solve was to fix almost everything — type, spacing, the warm paper-and-ink base — and let exactly one thing vary: an accent color per room, used sparingly enough that color still <em>means</em> something (“which room am I in”) instead of just decorating the page.</p>
<p>Type is doing more work than color, actually. Headlines and the wordmark are set in <strong>Instrument Serif</strong>, with the occasional word breaking into italic — <em>Research</em> — a signature move I made myself use sparingly, at most once per view, after an early draft turned it into a tic. Long-form essay text sits in <strong>Newsreader</strong>, sized and leaded for actual reading rather than scanning. Numerals — years in a publication list, in a BibTeX block — get <strong>JetBrains Mono</strong>, and nowhere else; an earlier pass had mono-caps in the navigation and it immediately read as a developer’s terminal rather than someone’s front door, so that idea died fast.</p>
<blockquote>
<p>Color always means “which room am I in,” never decoration.</p>
</blockquote>
<p>Research got a blue that reads scholarly and a little cold on purpose; Work got a green that’s meant to feel dependable; Life got a warm orange-red, on paper that warms half a shade to match. Dark mode isn’t an inversion — it’s a second, separately tuned palette, system-synced by default with a manual override that remembers your choice.</p>
<p>The tokens themselves, for anyone curious enough to check the CSS:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="css"><code><span class="line"><span style="color:#6A737D">/* base — light */</span></span>
<span class="line"><span style="color:#E1E4E8">--paper: </span><span style="color:#FDAEB7;font-style:italic">#F7F2E9;</span><span style="color:#E1E4E8">  --ink: </span><span style="color:#FDAEB7;font-style:italic">#1C1712</span><span style="color:#E1E4E8">;  --ink-2: </span><span style="color:#FDAEB7;font-style:italic">#6C6053</span><span style="color:#E1E4E8">;  --ink-3: </span><span style="color:#FDAEB7;font-style:italic">#A2937F;</span></span>
<span class="line"><span style="color:#6A737D">/* base — dark */</span></span>
<span class="line"><span style="color:#E1E4E8">--paper: </span><span style="color:#FDAEB7;font-style:italic">#141009</span><span style="color:#E1E4E8">;  --ink: </span><span style="color:#FDAEB7;font-style:italic">#F2EADC;</span><span style="color:#E1E4E8">  --ink-2: </span><span style="color:#FDAEB7;font-style:italic">#A99A85;</span><span style="color:#E1E4E8">  --ink-3: </span><span style="color:#FDAEB7;font-style:italic">#6E6252</span><span style="color:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D">/* rooms      light      dark    */</span></span>
<span class="line"><span style="color:#E1E4E8">--research:  </span><span style="color:#FDAEB7;font-style:italic">#2447C5</span><span style="color:#E1E4E8">;   </span><span style="color:#FDAEB7;font-style:italic">#7B94FF</span><span style="color:#E1E4E8">;</span></span>
<span class="line"><span style="color:#E1E4E8">--work:      </span><span style="color:#FDAEB7;font-style:italic">#166E5A</span><span style="color:#E1E4E8">;   </span><span style="color:#FDAEB7;font-style:italic">#4CC7A4</span><span style="color:#E1E4E8">;</span></span>
<span class="line"><span style="color:#E1E4E8">--life:      </span><span style="color:#FDAEB7;font-style:italic">#D14E24;</span><span style="color:#FDAEB7;font-style:italic">   #FF7847;</span></span></code></pre>
<h3 id="building-it">Building it</h3>
<p>The honest version of this story includes a false start. An earlier attempt at rebuilding the site tried to do the room-separation via subdomains, three fully separate themes, and <a href="https://strapi.io">Strapi</a> — a headless CMS — running in its own Docker container. It was technically impressive and operationally exhausting: every room ended up looking like it came from a different template rather than one house, and writing a single post meant a server had to be up somewhere first. I shelved it. The only thing worth keeping was the thinking around how publication data should be modeled, which survived into this version.</p>
<p>What I actually wanted was smaller than a CMS with more features — it was the ability to write a post from whatever device I had open, without spinning anything up first. That’s what sent me looking past headless CMSes entirely, toward something that would commit straight to Git. What shipped reflects that: a static Astro site, one content pipeline where a post declares which room(s) it belongs to in its front matter, no CSS framework — just custom properties and plain CSS, because the design system is small enough that a framework would be more ceremony than help. Editing happens through <a href="https://pagescms.org">Pages CMS</a>, a lightweight browser editor that commits straight to this repo and triggers a deploy — no admin server to run, no separate database to back up. I’m typing this very announcement into a form field, and in a few minutes it’ll be a live page.</p>
<p><em>Built with:</em></p>
<div style="display:flex; flex-wrap:wrap; gap:28px; justify-content:center; margin:0.6em 0 0.2em;">
  <div style="display:flex; flex-direction:column; align-items:center; gap:6px; width:78px;">
    <svg width="30" height="30" viewBox="0 0 24 24" fill="#BC52EE" aria-hidden="true"><path d="M8.358 20.162c-1.186-1.07-1.532-3.316-1.038-4.944.856 1.026 2.043 1.352 3.272 1.535 1.897.283 3.76.177 5.522-.678.202-.098.388-.229.608-.36.166.473.209.95.151 1.437-.14 1.185-.738 2.1-1.688 2.794-.38.277-.782.525-1.175.787-1.205.804-1.531 1.747-1.078 3.119l.044.148a3.158 3.158 0 0 1-1.407-1.188 3.31 3.31 0 0 1-.544-1.815c-.004-.32-.004-.642-.048-.958-.106-.769-.472-1.113-1.161-1.133-.707-.02-1.267.411-1.415 1.09-.012.053-.028.104-.045.165h.002zm-5.961-4.445s3.24-1.575 6.49-1.575l2.451-7.565c.092-.366.36-.614.662-.614.302 0 .57.248.662.614l2.45 7.565c3.85 0 6.491 1.575 6.491 1.575L16.088.727C15.93.285 15.663 0 15.303 0H8.697c-.36 0-.615.285-.784.727l-5.516 14.99z"></path></svg>
    <span style="font-size:12px; color:var(--ink-3);">Astro</span>
  </div>
  <div style="display:flex; flex-direction:column; align-items:center; gap:6px; width:78px;">
    <svg width="30" height="30" viewBox="0 0 24 24" fill="#3178C6" aria-hidden="true"><path d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z"></path></svg>
    <span style="font-size:12px; color:var(--ink-3);">TypeScript</span>
  </div>
  <div style="display:flex; flex-direction:column; align-items:center; gap:6px; width:78px;">
    <svg width="30" height="30" viewBox="0 0 24 24" fill="#F38020" aria-hidden="true"><path d="M10.715 14.32H5.442l-.64-1.203L13.673 0l1.397.579-1.752 9.112h5.24l.648 1.192L10.719 24l-1.412-.54ZM4.091 5.448a.5787.5787 0 1 1 0-1.1574.5787.5787 0 0 1 0 1.1574zm1.543 0a.5787.5787 0 1 1 0-1.1574.5787.5787 0 0 1 0 1.1574zm1.544 0a.5787.5787 0 1 1 0-1.1574.5787.5787 0 0 1 0 1.1574zm8.657-2.7h5.424l.772.771v16.975l-.772.772h-7.392l.374-.579h6.779l.432-.432V3.758l-.432-.432h-4.676l-.552 2.85h-.59l.529-2.877.108-.552ZM2.74 21.265l-.772-.772V3.518l.772-.771h7.677l-.386.579H2.98l-.432.432v16.496l.432.432h5.586l-.092.579zm1.157-1.93h3.28l-.116.58h-3.55l-.192-.193v-3.473l.578 1.158zm13.117 0 .579.58H14.7l.385-.58z"></path></svg>
    <span style="font-size:12px; color:var(--ink-3);">Cloudflare Pages</span>
  </div>
  <div style="display:flex; flex-direction:column; align-items:center; gap:6px; width:78px;">
    <svg width="30" height="30" viewBox="0 0 24 24" fill="#2088FF" aria-hidden="true"><path d="M10.984 13.836a.5.5 0 0 1-.353-.146l-.745-.743a.5.5 0 1 1 .706-.708l.392.391 1.181-1.18a.5.5 0 0 1 .708.707l-1.535 1.533a.504.504 0 0 1-.354.146zm9.353-.147l1.534-1.532a.5.5 0 0 0-.707-.707l-1.181 1.18-.392-.391a.5.5 0 1 0-.706.708l.746.743a.497.497 0 0 0 .706-.001zM4.527 7.452l2.557-1.585A1 1 0 0 0 7.09 4.17L4.533 2.56A1 1 0 0 0 3 3.406v3.196a1.001 1.001 0 0 0 1.527.85zm2.03-2.436L4 6.602V3.406l2.557 1.61zM24 12.5c0 1.93-1.57 3.5-3.5 3.5a3.503 3.503 0 0 1-3.46-3h-2.08a3.503 3.503 0 0 1-3.46 3 3.502 3.502 0 0 1-3.46-3h-.558c-.972 0-1.85-.399-2.482-1.042V17c0 1.654 1.346 3 3 3h.04c.244-1.693 1.7-3 3.46-3 1.93 0 3.5 1.57 3.5 3.5S13.43 24 11.5 24a3.502 3.502 0 0 1-3.46-3H8c-2.206 0-4-1.794-4-4V9.899A5.008 5.008 0 0 1 0 5c0-2.757 2.243-5 5-5s5 2.243 5 5a5.005 5.005 0 0 1-4.952 4.998A2.482 2.482 0 0 0 7.482 12h.558c.244-1.693 1.7-3 3.46-3a3.502 3.502 0 0 1 3.46 3h2.08a3.503 3.503 0 0 1 3.46-3c1.93 0 3.5 1.57 3.5 3.5zm-15 8c0 1.378 1.122 2.5 2.5 2.5s2.5-1.122 2.5-2.5-1.122-2.5-2.5-2.5S9 19.122 9 20.5zM5 9c2.206 0 4-1.794 4-4S7.206 1 5 1 1 2.794 1 5s1.794 4 4 4zm9 3.5c0-1.378-1.122-2.5-2.5-2.5S9 11.122 9 12.5s1.122 2.5 2.5 2.5 2.5-1.122 2.5-2.5zm9 0c0-1.378-1.122-2.5-2.5-2.5S18 11.122 18 12.5s1.122 2.5 2.5 2.5 2.5-1.122 2.5-2.5zm-13 8a.5.5 0 1 0 1 0 .5.5 0 0 0-1 0zm2 0a.5.5 0 1 0 1 0 .5.5 0 0 0-1 0zm12 0c0 1.93-1.57 3.5-3.5 3.5a3.503 3.503 0 0 1-3.46-3.002c-.007.001-.013.005-.021.005l-.506.017h-.017a.5.5 0 0 1-.016-.999l.506-.017c.018-.002.035.006.052.007A3.503 3.503 0 0 1 20.5 17c1.93 0 3.5 1.57 3.5 3.5zm-1 0c0-1.378-1.122-2.5-2.5-2.5S18 19.122 18 20.5s1.122 2.5 2.5 2.5 2.5-1.122 2.5-2.5z"></path></svg>
    <span style="font-size:12px; color:var(--ink-3);">GitHub Actions</span>
  </div>
  <div style="display:flex; flex-direction:column; align-items:center; gap:6px; width:78px;">
    <svg width="30" height="30" viewBox="0 0 24 24" fill="#111111" aria-hidden="true"><path d="M18 6a6 6 0 10-6 6 6 6 0 015.35 9h1.5A7.5 7.5 0 0012 10.5 4.5 4.5 0 1116.5 6Zm-6-3a3 3 0 000 6 1 1 0 000-6m0 1.5a1.5 1.5 0 010 3 1 1 0 010-3M7.5 15v1.5H9v6H4.5V24h15v-1.5H15v-6h1.5V15Zm3 1.5h3v6h-3zm-6 1.5a7.5 7.5 0 00.7 3h1.5a6 6 0 01-.7-3Z"></path></svg>
    <span style="font-size:12px; color:var(--ink-3);">Simple Icons</span>
  </div>
</div>
<h3 id="under-the-hood">Under the hood</h3>
<p>Content lives in a couple of Astro content collections, each checked against a schema — a post’s <code>rooms</code> array has to contain at least one of <code>research | work | life</code>, dates get coerced automatically, and anything that doesn’t match fails the build rather than showing up broken in someone’s browser. One shared layout renders a post regardless of which room it’s in, which is also why something like an optional cover photo only had to be written once to work everywhere.</p>
<p>Routing follows the room structure directly — no server, no database, just static files generated at build time:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="mermaid"><code><span class="line"><span style="color:#E1E4E8">graph TD</span></span>
<span class="line"><span style="color:#E1E4E8">  classDef research fill:#2447C5,stroke:#2447C5,color:#fff</span></span>
<span class="line"><span style="color:#E1E4E8">  classDef work fill:#166E5A,stroke:#166E5A,color:#fff</span></span>
<span class="line"><span style="color:#E1E4E8">  classDef life fill:#D14E24,stroke:#D14E24,color:#fff</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">  T["/ — threshold"] --> R["/research"]:::research</span></span>
<span class="line"><span style="color:#E1E4E8">  T --> W["/work"]:::work</span></span>
<span class="line"><span style="color:#E1E4E8">  T --> L["/life"]:::life</span></span>
<span class="line"><span style="color:#E1E4E8">  R --> RP["publications"]:::research</span></span>
<span class="line"><span style="color:#E1E4E8">  R --> RN["notes"]:::research</span></span>
<span class="line"><span style="color:#E1E4E8">  R --> RC["cv"]:::research</span></span>
<span class="line"><span style="color:#E1E4E8">  R --> RCon["contact"]:::research</span></span>
<span class="line"><span style="color:#E1E4E8">  W --> WN["notes"]:::work</span></span>
<span class="line"><span style="color:#E1E4E8">  W --> WC["cv"]:::work</span></span>
<span class="line"><span style="color:#E1E4E8">  W --> WCon["contact"]:::work</span></span>
<span class="line"><span style="color:#E1E4E8">  L --> LE["essays"]:::life</span></span>
<span class="line"><span style="color:#E1E4E8">  L --> LS["shelf"]:::life</span></span>
<span class="line"><span style="color:#E1E4E8">  L --> LA["about"]:::life</span></span></code></pre>
<p><em>Fig. 1 — routing, colored by room: research in blue, work in green, life in orange.</em></p>
<p>The node colors above are the exact room tokens from the block earlier — not a coincidence, the diagram is styled from the same three hex values as the site.</p>
<p>Deployment is the same shape as the CMS itself: everything funnels down to a single <code>git push</code> to the <code>v2</code> branch, whether that push comes from a terminal or from Pages CMS saving a form.</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="mermaid"><code><span class="line"><span style="color:#E1E4E8">graph LR</span></span>
<span class="line"><span style="color:#E1E4E8">  classDef gha stroke:#2088FF,stroke-width:2px</span></span>
<span class="line"><span style="color:#E1E4E8">  classDef cf stroke:#F38020,stroke-width:2px</span></span>
<span class="line"><span style="color:#E1E4E8">  classDef logo stroke:#A2937F,stroke-width:1.5px</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">  A["Edit in Pages CMS"] --> B["&#x3C;span>&#x3C;img src='/assets/images/icons/github.svg' width='24' height='24'/>&#x3C;/span>"]</span></span>
<span class="line"><span style="color:#E1E4E8">  C["&#x3C;span>&#x3C;img src='/assets/images/icons/git.svg' width='24' height='24'/>&#x3C;/span>"] --> B</span></span>
<span class="line"><span style="color:#E1E4E8">  B --> D["&#x3C;img src='/assets/images/icons/github-actions.svg' width='22' height='22'/>&#x26;nbsp;&#x3C;img src='/assets/images/icons/astro.svg' width='22' height='22'/>"]:::gha</span></span>
<span class="line"><span style="color:#E1E4E8">  D --> E["&#x3C;img src='/assets/images/icons/cloudflare-pages.svg' width='22' height='22'/>&#x26;nbsp;&#x3C;img src='/assets/images/icons/rocket.svg' width='22' height='22'/>"]:::cf</span></span>
<span class="line"><span style="color:#E1E4E8">  E --> F["&#x3C;span>&#x3C;img src='/assets/images/icons/threshold-lines.svg' width='34' height='34'/>&#x3C;/span>"]:::logo</span></span></code></pre>
<p><em>Fig. 2 — an edit becomes a live page: git/GitHub, GitHub Actions running an Astro build, Cloudflare Pages deploying it, landing at ali.mk.</em></p>
<p>Nothing to patch, nothing to back up, no build step I have to remember to run by hand — the whole loop from “edit a field” to “it’s live” takes under a minute.</p>
<p>Zoomed out, the whole system is small enough to draw on one diagram: content and code meet at the <code>v2</code> branch, GitHub Actions turns that into static files, Cloudflare serves them at the edge, and a visitor’s browser reports back a single privacy-respecting pageview.</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="mermaid"><code><span class="line"><span style="color:#E1E4E8">graph TB</span></span>
<span class="line"><span style="color:#E1E4E8">  classDef gha fill:#2088FF,stroke:#2088FF,color:#fff</span></span>
<span class="line"><span style="color:#E1E4E8">  classDef cf fill:#F38020,stroke:#F38020,color:#fff</span></span>
<span class="line"><span style="color:#E1E4E8">  classDef gc fill:#0EA5A0,stroke:#0EA5A0,color:#fff</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">  subgraph Authoring</span></span>
<span class="line"><span style="color:#E1E4E8">    CMS["Pages CMS&#x3C;br/>(browser form)"]</span></span>
<span class="line"><span style="color:#E1E4E8">    Term["Terminal&#x3C;br/>(git push)"]</span></span>
<span class="line"><span style="color:#E1E4E8">  end</span></span>
<span class="line"><span style="color:#E1E4E8">  CMS -->|commit| Repo["GitHub&#x3C;br/>v2 branch"]</span></span>
<span class="line"><span style="color:#E1E4E8">  Term -->|push| Repo</span></span>
<span class="line"><span style="color:#E1E4E8">  Repo --> CI["GitHub Actions&#x3C;br/>astro build"]:::gha</span></span>
<span class="line"><span style="color:#E1E4E8">  CI -->|static HTML/CSS/JS| CDN["Cloudflare Pages&#x3C;br/>edge network"]:::cf</span></span>
<span class="line"><span style="color:#E1E4E8">  CDN --> Visitor["Visitor's browser"]</span></span>
<span class="line"><span style="color:#E1E4E8">  Visitor -.->|one pageview,&#x3C;br/>no cookies| GC["GoatCounter"]:::gc</span></span></code></pre>
<p><em>Fig. 3 — the whole system in one picture: authoring, build, hosting, and analytics.</em></p>
<h3 id="analytics-briefly">Analytics, briefly</h3>
<p>The pageview count on this site comes from <a href="https://www.goatcounter.com/">GoatCounter</a> — open source, no cookies, no personal data collected, nothing to justify in a cookie banner because there’s nothing to consent to. The only wrinkle is that this site does client-side page transitions (Astro’s view transitions swap content without a full reload), so a plain analytics snippet that only fires <code>onload</code> would count the first page of every visit and miss the rest. The fix was small: disable GoatCounter’s automatic count and fire it manually on <code>astro:page-load</code>, an event Astro dispatches on the initial load <em>and</em> every soft navigation after it — so every room, every essay, every publication page gets counted exactly once, however someone got there.</p>
<h3 id="standing-on-open-source">Standing on open source</h3>
<p>None of this exists without a long list of people who gave their work away for free. This site runs on <a href="https://astro.build">Astro</a> and <a href="https://www.typescriptlang.org/">TypeScript</a>, validates its content with <a href="https://zod.dev">Zod</a>, renders the diagrams above with <a href="https://mermaid.js.org/">Mermaid</a>, highlights its code blocks with Shiki (bundled straight into Astro), draws its brand logos from <a href="https://simpleicons.org">Simple Icons</a>, sets its type with self-hosted <a href="https://fontsource.org">Fontsource</a> packages of Instrument Sans, Instrument Serif, Newsreader, and JetBrains Mono, and gets edited through <a href="https://pagescms.org">Pages CMS</a> — a genuinely lovely piece of software for something I don’t pay a cent for. <a href="https://www.goatcounter.com/">GoatCounter</a> covers analytics, <a href="https://github.com/features/actions">GitHub Actions</a> covers the build, and <a href="https://pages.cloudflare.com/">Cloudflare Pages</a> covers hosting, all on free tiers that exist because someone decided small personal projects deserve good infrastructure too. And further back, this whole habit started with <a href="https://jekyllrb.com/">Jekyll</a> and the <a href="https://chirpy.cotes.page/">Chirpy</a> theme, which is still out there being maintained by people who owe me nothing.</p>
<p>If you maintain any of the above: thank you. Genuinely.</p>
<h3 id="what-its-for">What it’s for</h3>
<p>The point was never to look different for its own sake. It was to stop asking one page to perform three roles simultaneously, and to stop <em>self-censoring by architecture</em> — quietly softening an opinion, or leaving out a film review, because it might sit two scrolls away from someone deciding whether to fund my next project. Now the writing can be as direct as it needs to be in whichever room it belongs to, because the room it belongs to is the only room it’s in.</p>
<p>Come in through whichever door fits why you’re here. Or, if you’re curious, try all three — that’s kind of the point of having them.</p>]]></content></entry><entry><title>My Favorite Research Tools</title><id>https://ali.mk/posts/my-favorite-research-tools/</id><link href="https://ali.mk/posts/my-favorite-research-tools/" /><published>2024-02-14T00:00:00.000Z</published><updated>2024-02-14T00:00:00.000Z</updated><summary>Reference managers, annotation, and the glue between them.</summary><category term="research" /><category term="apps" /><category term="reference" /><category term="literature" /><content type="html"><![CDATA[<h2 id="reference-management">Reference Management</h2>
<h3 id="zotero"><a href="https://zotero.org">Zotero</a></h3>
<p><img src="https://www.zotero.org/static/images/promote/zotero-logo-512x123.svg" alt="Zotero Logo"></p>
<h4 id="add-ons--plugins">Add-ons &#x26; Plugins</h4>
<p>The main advantage of Zotero is that you can install <a href="https://www.zotero.org/support/plugins">plugins and add-ons</a> to extend its functionality. Here are some of the most useful ones for me:</p>
<ul>
<li><a href="https://retorque.re/zotero-better-bibtex/">Better BibTex</a>: This plugin allows you to export your references in a variety of formats, including BibTeX, which is essential for LaTeX users.</li>
<li><a href="https://github.com/scitedotai/scite-zotero-plugin">Scite zotero plugin</a></li>
</ul>]]></content></entry><entry><title>Useful LaTeX Packages for Scientific Writing</title><id>https://ali.mk/posts/useful-latex-packages/</id><link href="https://ali.mk/posts/useful-latex-packages/" /><published>2024-01-19T00:00:00.000Z</published><updated>2024-01-19T00:00:00.000Z</updated><summary>The short list that survives every paper.</summary><category term="latex" /><category term="packages" /><category term="writing" /><content type="html"><![CDATA[<style>
    .table td:last-child {
        white-space: normal;
        word-wrap: break-word;
    }
</style>















<table><thead><tr><th>Package</th><th>Links</th><th>What it does</th></tr></thead><tbody><tr><td>Changes</td><td><a href="https://changes.sourceforge.net/">Homepage</a> · <a href="https://ctan.org/pkg/changes">CTAN</a></td><td>Tracking changes in a document. Useful for doing a paper revision after getting the reviews.</td></tr></tbody></table>]]></content></entry><entry><title>ABC of SSH: An Introduction</title><id>https://ali.mk/posts/ssh-tutorial/</id><link href="https://ali.mk/posts/ssh-tutorial/" /><published>2024-01-14T00:00:00.000Z</published><updated>2024-01-14T00:00:00.000Z</updated><summary>The remote-work workflow I teach every new student.</summary><category term="network" /><category term="SSH" /><category term="server" /><content type="html"><![CDATA[<p>SSH, or Secure Shell, is a network protocol that allows you to securely connect and communicate with remote servers over the internet. With SSH, you can run commands, transfer files, and configure services on remote machines. SSH also supports various authentication methods, such as passwords and public-key cryptography.</p>
<p>In this post, we will focus on the public-key authentication method, which is more secure and convenient than using passwords. We will explain what SSH keys are, how they work, and how to create and use them on different operating systems, such as Windows 11, MacOS, and Ubuntu.</p>
<h2 id="what-are-ssh-keys">What are SSH keys?</h2>
<p>SSH keys are two long strings of characters that are used to verify the identity of a user who wants to access a remote server. These keys are generated by the user on their local machine using a SSH utility. One key is private and stored on the user’s local machine. The other key is public and shared with the remote server or any other entity the user wishes to securely communicate with.</p>
<p>The private key is like a secret password that should never be revealed to anyone. The public key is like a lock that can be opened only by the matching private key. When the user tries to connect to the remote server, the server will check if the user has the correct private key that matches the public key stored on the server. If the keys match, the user is granted access. If not, the connection is denied.</p>
<p>SSH keys provide several advantages over passwords:</p>
<ul>
<li>They are more secure, as they are harder to guess or crack by brute force attacks.</li>
<li>They are more convenient, as they do not require the user to remember or type a password every time they connect to the server.</li>
<li>They can be used to automate tasks, such as running scripts or deploying applications, without human intervention.</li>
</ul>
<h2 id="how-to-create-ssh-keys">How to create SSH keys?</h2>
<p>To create SSH keys, you need to use a SSH utility that is available on your operating system. There are different tools and commands for different operating systems, but the basic steps are similar:</p>
<ul>
<li>Run a command to generate a pair of SSH keys, usually a 3072-bit or 4096-bit RSA key pair. You can optionally add a passphrase to further protect your private key.</li>
<li>Save the keys in a secure location on your local machine, usually in a hidden folder named <code>.ssh</code> in your home directory. The private key will have no file extension, while the public key will have a <code>.pub</code> extension.</li>
<li>Copy the public key to the remote server or any other entity you want to communicate with. You can use a utility called <code>ssh-copy-id</code> or manually append the public key to a file named <code>authorized_keys</code> in the <code>.ssh</code> folder on the remote server.</li>
</ul>
<p>In the following sections, we will show you how to create SSH keys on Windows 11, MacOS, and Ubuntu, using different tools and commands.</p>
<h3 id="windows-11">Windows 11</h3>
<p>Windows 11 comes with a built-in OpenSSH client that you can use to generate SSH keys. To use it, open the Windows Terminal or the Command Prompt and follow these steps:</p>
<ul>
<li>Type the following command to generate a pair of SSH keys and press Enter:</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh-keygen</span><span style="color:#79B8FF"> -t</span><span style="color:#9ECBFF"> rsa</span><span style="color:#79B8FF"> -b</span><span style="color:#79B8FF"> 4096</span><span style="color:#79B8FF"> -C</span><span style="color:#9ECBFF"> "your_email@example.com"</span></span></code></pre>
<p>This will create a 4096-bit RSA key pair with your email address as a comment.</p>
<ul>
<li>You will be prompted to specify the file name and location for the keys. Press Enter to accept the default location, which is <code>C:\Users\yourusername\.ssh\id_rsa</code> for the private key and <code>C:\Users\yourusername\.ssh\id_rsa.pub</code> for the public key.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Enter</span><span style="color:#9ECBFF"> file</span><span style="color:#9ECBFF"> in</span><span style="color:#9ECBFF"> which</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> save</span><span style="color:#9ECBFF"> the</span><span style="color:#9ECBFF"> key</span><span style="color:#E1E4E8"> (C:</span><span style="color:#79B8FF">\U</span><span style="color:#E1E4E8">sers</span><span style="color:#79B8FF">\y</span><span style="color:#E1E4E8">ourusername/.ssh/id_rsa):</span></span></code></pre>
<ul>
<li>You will be asked to enter a passphrase for the keys. This is optional, but recommended for extra security. Type a secure passphrase and press Enter. You will need to enter the same passphrase again to confirm it.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Enter</span><span style="color:#9ECBFF"> passphrase</span><span style="color:#E1E4E8"> (empty </span><span style="color:#9ECBFF">for</span><span style="color:#9ECBFF"> no</span><span style="color:#9ECBFF"> passphrase</span><span style="color:#E1E4E8">):</span></span>
<span class="line"><span style="color:#B392F0">Enter</span><span style="color:#9ECBFF"> same</span><span style="color:#9ECBFF"> passphrase</span><span style="color:#9ECBFF"> again:</span></span></code></pre>
<ul>
<li>You will see a message that your keys have been generated, along with a fingerprint and a randomart image.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Your</span><span style="color:#9ECBFF"> identification</span><span style="color:#9ECBFF"> has</span><span style="color:#9ECBFF"> been</span><span style="color:#9ECBFF"> saved</span><span style="color:#9ECBFF"> in</span><span style="color:#9ECBFF"> C:</span><span style="color:#79B8FF">\U</span><span style="color:#9ECBFF">sers</span><span style="color:#79B8FF">\y</span><span style="color:#9ECBFF">ourusername/.ssh/id_rsa</span></span>
<span class="line"><span style="color:#B392F0">Your</span><span style="color:#9ECBFF"> public</span><span style="color:#9ECBFF"> key</span><span style="color:#9ECBFF"> has</span><span style="color:#9ECBFF"> been</span><span style="color:#9ECBFF"> saved</span><span style="color:#9ECBFF"> in</span><span style="color:#9ECBFF"> C:</span><span style="color:#79B8FF">\U</span><span style="color:#9ECBFF">sers</span><span style="color:#79B8FF">\y</span><span style="color:#9ECBFF">ourusername/.ssh/id_rsa.pub</span></span>
<span class="line"><span style="color:#B392F0">The</span><span style="color:#9ECBFF"> key</span><span style="color:#9ECBFF"> fingerprint</span><span style="color:#9ECBFF"> is:</span></span>
<span class="line"><span style="color:#B392F0">SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span><span style="color:#9ECBFF"> your_email@example.com</span></span>
<span class="line"><span style="color:#B392F0">The</span><span style="color:#9ECBFF"> key's randomart image is:</span></span>
<span class="line"><span style="color:#9ECBFF">+---[RSA 4096]----+</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">+----[SHA256]-----+</span></span></code></pre>
<ul>
<li>To copy the public key to the remote server, you can use the <code>ssh-copy-id</code> utility. Type the following command, replacing <code>remote_username</code> and <code>server_ip_address</code> with the username and IP address of the remote server. You will be prompted to enter the password of the remote user.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="shell"><code><span class="line"><span style="color:#B392F0">ssh-copy-id</span><span style="color:#9ECBFF"> remote_username@server_ip_address</span></span></code></pre>
<ul>
<li>Alternatively, you can manually copy the public key to the remote server. To do that, you need to open the public key file with a text editor, such as Notepad, and copy its contents. Then, you need to log in to the remote server using SSH, create a <code>.ssh</code> folder in your home directory if it does not exist, and append the public key to a file named <code>authorized_keys</code> in the <code>.ssh</code> folder. You can use the following commands to do that:</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="shell"><code><span class="line"><span style="color:#B392F0">ssh</span><span style="color:#9ECBFF"> remote_username@server_ip_address</span></span>
<span class="line"><span style="color:#B392F0">mkdir</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> ~/.ssh</span></span>
<span class="line"><span style="color:#79B8FF">echo</span><span style="color:#9ECBFF"> 'paste_your_public_key_here'</span><span style="color:#F97583"> >></span><span style="color:#9ECBFF"> ~/.ssh/authorized_keys</span></span></code></pre>
<h3 id="macos">MacOS</h3>
<p>MacOS comes with a SSH utility called OpenSSH that you can use to generate SSH keys. To use it, open the Terminal application and follow these steps:</p>
<ul>
<li>Type the following command to generate a pair of SSH keys and press Enter:</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh-keygen</span><span style="color:#79B8FF"> -t</span><span style="color:#9ECBFF"> rsa</span><span style="color:#79B8FF"> -b</span><span style="color:#79B8FF"> 4096</span><span style="color:#79B8FF"> -C</span><span style="color:#9ECBFF"> "your_email@example.com"</span></span></code></pre>
<p>This will create a 4096-bit RSA key pair with your email address as a comment.</p>
<ul>
<li>You will be prompted to specify the file name and location for the keys. Press Enter to accept the default location, which is <code>/Users/yourusername/.ssh/id_rsa</code> for the private key and <code>/Users/yourusername/.ssh/id_rsa.pub</code> for the public key.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Enter</span><span style="color:#9ECBFF"> file</span><span style="color:#9ECBFF"> in</span><span style="color:#9ECBFF"> which</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> save</span><span style="color:#9ECBFF"> the</span><span style="color:#9ECBFF"> key</span><span style="color:#E1E4E8"> (/Users/yourusername/.ssh/id_rsa):</span></span></code></pre>
<ul>
<li>You will be asked to enter a passphrase for the keys. This is optional, but recommended for extra security. Type a secure passphrase and press Enter. You will need to enter the same passphrase again to confirm it.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Enter</span><span style="color:#9ECBFF"> passphrase</span><span style="color:#E1E4E8"> (empty </span><span style="color:#9ECBFF">for</span><span style="color:#9ECBFF"> no</span><span style="color:#9ECBFF"> passphrase</span><span style="color:#E1E4E8">):</span></span>
<span class="line"><span style="color:#B392F0">Enter</span><span style="color:#9ECBFF"> same</span><span style="color:#9ECBFF"> passphrase</span><span style="color:#9ECBFF"> again:</span></span></code></pre>
<ul>
<li>You will see a message that your keys have been generated, along with a fingerprint and a randomart image.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Your</span><span style="color:#9ECBFF"> identification</span><span style="color:#9ECBFF"> has</span><span style="color:#9ECBFF"> been</span><span style="color:#9ECBFF"> saved</span><span style="color:#9ECBFF"> in</span><span style="color:#9ECBFF"> /Users/yourusername/.ssh/id_rsa</span></span>
<span class="line"><span style="color:#B392F0">Your</span><span style="color:#9ECBFF"> public</span><span style="color:#9ECBFF"> key</span><span style="color:#9ECBFF"> has</span><span style="color:#9ECBFF"> been</span><span style="color:#9ECBFF"> saved</span><span style="color:#9ECBFF"> in</span><span style="color:#9ECBFF"> /Users/yourusername/.ssh/id_rsa.pub</span></span>
<span class="line"><span style="color:#B392F0">The</span><span style="color:#9ECBFF"> key</span><span style="color:#9ECBFF"> fingerprint</span><span style="color:#9ECBFF"> is:</span></span>
<span class="line"><span style="color:#B392F0">SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span><span style="color:#9ECBFF"> your_email@example.com</span></span>
<span class="line"><span style="color:#B392F0">The</span><span style="color:#9ECBFF"> key's randomart image is:</span></span>
<span class="line"><span style="color:#9ECBFF">+---[RSA 4096]----+</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">+----[SHA256]-----+</span></span></code></pre>
<ul>
<li>To copy the public key to the remote server, you can use the <code>ssh-copy-id</code> utility. Type the following command, replacing <code>remote_username</code> and <code>server_ip_address</code> with the username and IP address of the remote server. You will be prompted to enter the password of the remote user.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh-copy-id</span><span style="color:#9ECBFF"> remote_username@server_ip_address</span></span></code></pre>
<ul>
<li>Alternatively, you can manually copy the public key to the remote server. To do that, you need to open the public key file with a text editor, such as TextEdit, and copy its contents. Then, you need to log in to the remote server using SSH, create a <code>.ssh</code> folder in your home directory if it does not exist, and append the public key to a file named <code>authorized_keys</code> in the <code>.ssh</code> folder. You can use the following commands to do that:</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh</span><span style="color:#9ECBFF"> remote_username@server_ip_address</span></span>
<span class="line"><span style="color:#B392F0">mkdir</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> ~/.ssh</span></span>
<span class="line"><span style="color:#79B8FF">echo</span><span style="color:#9ECBFF"> 'paste_your_public_key_here'</span><span style="color:#F97583"> >></span><span style="color:#9ECBFF"> ~/.ssh/authorized_keys</span></span></code></pre>
<h3 id="ubuntu">Ubuntu</h3>
<p>Ubuntu comes with a SSH utility called OpenSSH that you can use to generate SSH keys. To use it, open the Terminal application and follow these steps:</p>
<ul>
<li>Type the following command to generate a pair of SSH keys and press Enter:</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh-keygen</span><span style="color:#79B8FF"> -t</span><span style="color:#9ECBFF"> rsa</span><span style="color:#79B8FF"> -b</span><span style="color:#79B8FF"> 4096</span><span style="color:#79B8FF"> -C</span><span style="color:#9ECBFF"> "your_email@example.com"</span></span></code></pre>
<p>This will create a 4096-bit RSA key pair with your email address as a comment.</p>
<ul>
<li>You will be prompted to specify the file name and location for the keys. Press Enter to accept the default location, which is <code>/home/yourusername/.ssh/id_rsa</code> for the private key and <code>/home/yourusername/.ssh/id_rsa.pub</code> for the public key.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Enter</span><span style="color:#9ECBFF"> file</span><span style="color:#9ECBFF"> in</span><span style="color:#9ECBFF"> which</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> save</span><span style="color:#9ECBFF"> the</span><span style="color:#9ECBFF"> key</span><span style="color:#E1E4E8"> (/home/yourusername/.ssh/id_rsa):</span></span></code></pre>
<ul>
<li>You will be asked to enter a passphrase for the keys. This is optional, but recommended for extra security. Type a secure passphrase and press Enter. You will need to enter the same passphrase again to confirm it.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Enter</span><span style="color:#9ECBFF"> passphrase</span><span style="color:#E1E4E8"> (empty </span><span style="color:#9ECBFF">for</span><span style="color:#9ECBFF"> no</span><span style="color:#9ECBFF"> passphrase</span><span style="color:#E1E4E8">):</span></span>
<span class="line"><span style="color:#B392F0">Enter</span><span style="color:#9ECBFF"> same</span><span style="color:#9ECBFF"> passphrase</span><span style="color:#9ECBFF"> again:</span></span></code></pre>
<ul>
<li>You will see a message that your keys have been generated, along with a fingerprint and a randomart image.</li>
</ul>
<p>Your identification has been saved in /home/yourusername/.ssh/id_rsa</p>
<p>OK, I will continue generating the blog post.</p>
<ul>
<li>You will see a message that your keys have been generated, along with a fingerprint and a randomart image.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Your</span><span style="color:#9ECBFF"> identification</span><span style="color:#9ECBFF"> has</span><span style="color:#9ECBFF"> been</span><span style="color:#9ECBFF"> saved</span><span style="color:#9ECBFF"> in</span><span style="color:#9ECBFF"> /home/yourusername/.ssh/id_rsa</span></span>
<span class="line"><span style="color:#B392F0">Your</span><span style="color:#9ECBFF"> public</span><span style="color:#9ECBFF"> key</span><span style="color:#9ECBFF"> has</span><span style="color:#9ECBFF"> been</span><span style="color:#9ECBFF"> saved</span><span style="color:#9ECBFF"> in</span><span style="color:#9ECBFF"> /home/yourusername/.ssh/id_rsa.pub</span></span>
<span class="line"><span style="color:#B392F0">The</span><span style="color:#9ECBFF"> key</span><span style="color:#9ECBFF"> fingerprint</span><span style="color:#9ECBFF"> is:</span></span>
<span class="line"><span style="color:#B392F0">SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span><span style="color:#9ECBFF"> your_email@example.com</span></span>
<span class="line"><span style="color:#B392F0">The</span><span style="color:#9ECBFF"> key's randomart image is:</span></span>
<span class="line"><span style="color:#9ECBFF">+---[RSA 4096]----+</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">|                 |</span></span>
<span class="line"><span style="color:#9ECBFF">+----[SHA256]-----+</span></span></code></pre>
<ul>
<li>To copy the public key to the remote server, you can use the <code>ssh-copy-id</code> utility. Type the following command, replacing <code>remote_username</code> and <code>server_ip_address</code> with the username and IP address of the remote server. You will be prompted to enter the password of the remote user.</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh-copy-id</span><span style="color:#9ECBFF"> remote_username@server_ip_address</span></span></code></pre>
<ul>
<li>Alternatively, you can manually copy the public key to the remote server. To do that, you need to open the public key file with a text editor, such as Gedit, and copy its contents. Then, you need to log in to the remote server using SSH, create a <code>.ssh</code> folder in your home directory if it does not exist, and append the public key to a file named <code>authorized_keys</code> in the <code>.ssh</code> folder. You can use the following commands to do that:</li>
</ul>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh</span><span style="color:#9ECBFF"> remote_username@server_ip_address</span></span>
<span class="line"><span style="color:#B392F0">mkdir</span><span style="color:#79B8FF"> -p</span><span style="color:#9ECBFF"> ~/.ssh</span></span>
<span class="line"><span style="color:#79B8FF">echo</span><span style="color:#9ECBFF"> 'paste_your_public_key_here'</span><span style="color:#F97583"> >></span><span style="color:#9ECBFF"> ~/.ssh/authorized_keys</span></span></code></pre>
<h2 id="how-to-use-ssh-keys">How to use SSH keys?</h2>
<p>Once you have created and copied your SSH keys, you can use them to connect to the remote server without entering a password. To do that, you need to use the <code>ssh</code> command with the <code>-i</code> option to specify the path to your private key. For example, to connect to the remote server using the private key stored in the default location, you can use the following command:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ssh</span><span style="color:#79B8FF"> -i</span><span style="color:#9ECBFF"> ~/.ssh/id_rsa</span><span style="color:#9ECBFF"> remote_username@server_ip_address</span></span></code></pre>
<p>If you have added a passphrase to your private key, you will be asked to enter it once per session. If you want to avoid typing the passphrase every time, you can use a utility called <code>ssh-agent</code> to store the passphrase in memory. To do that, you need to run the following commands:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#79B8FF">eval</span><span style="color:#E1E4E8"> $(</span><span style="color:#B392F0">ssh-agent</span><span style="color:#E1E4E8">)</span></span>
<span class="line"><span style="color:#B392F0">ssh-add</span><span style="color:#9ECBFF"> ~/.ssh/id_rsa</span></span></code></pre>
<p>You will be prompted to enter the passphrase once, and then it will be cached by the <code>ssh-agent</code>. You can then connect to the remote server using the <code>ssh</code> command without entering the passphrase again.</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this post, we have learned what SSH and SSH keys are, how they work, and how to create and use them on different operating systems. SSH keys are a secure and convenient way to access and communicate with remote servers over the internet. We hope you have found this post useful and informative. If you have any questions or feedback, please leave a comment below. Thank you for reading! 😊</p>]]></content></entry><entry><title>Platform Recommendations for Students</title><id>https://ali.mk/posts/platform-recommendations-for-students/</id><link href="https://ali.mk/posts/platform-recommendations-for-students/" /><published>2024-01-12T00:00:00.000Z</published><updated>2024-01-12T00:00:00.000Z</updated><summary>The tools I recommend to every thesis student I supervise.</summary><category term="platforms" /><category term="students" /><category term="tools" /><content type="html"><![CDATA[<p>In this post I describe the platforms I use for working. These platforms facilitate collaboration and boost teamwork. I recommend all my students to familiarize themselves with these platforms and use them for their projects and in communication with me.</p>
<h2 id="communication">Communication</h2>
<h3 id="slack">Slack</h3>
<p>I preffer to use Slack for work communication. I need to invite you to my workspace using Slack Connect. I will let you know about it.</p>
<h2 id="materials">Materials</h2>
<h3 id="user-interfanceexperience-uiux-design">User Interfance/Experience (UI/UX) Design</h3>
<p>Go through this part if your project includes a user interface design. If not, skip to the next section.</p>
<h4 id="prototyping">Prototyping</h4>
<h5 id="figma-recommended">Figma (Recommended)</h5>
<ol>
<li>Create an account on <a href="https://www.figma.com/">Figma</a></li>
<li>Register for <a href="https://www.figma.com/education/">Figma Education</a> using your KTH email</li>
</ol>
<h3 id="version-control">Version Control</h3>
<p>Needless to say that we will need a version control for our programming materials</p>
<h4 id="github">GitHub</h4>
<ol>
<li>Create an account on <a href="https://github.com/">GitHub</a> if you do not have one already</li>
<li>Register for <a href="https://education.github.com/">GitHub Education</a> and get verified as a student so that you can access the premium features for free and so many other benefits that I encourage you to use, such as <a href="https://copilot.github.com/">GitHub Copilot</a></li>
<li>Activate your GitHub Copilot</li>
<li>Create a private repository for your degree project/thesis and add me as a collaborator using my GitHub username <a href="https://github.com/horotat">@horotat</a></li>
</ol>
<h3 id="open-science-framework-osf">Open Science Framework (OSF)</h3>
<p>A healthy research ethics means not to be worried about sharing your work with others. If we are honest in all what we do, then we sholdn’t worry about sharing the details of our analsys, data, and methods with others. An open science attitude is a good way to give the other researchers the opportunity to reproduce your work and build on it. <a href="https://osf.io/">OSF</a> is a platform that facilitates this process. If you are going to work on a scientific project with me, I recommend you to:</p>
<ol>
<li>Create an account on OSF</li>
<li>Create a project for your degree project/thesis</li>
<li>Add me as a contributor using my KTH email</li>
<li>Keep the repository private for the time being</li>
<li>In our first meeting we will put the proposal on the OSF repo and build on top of that</li>
</ol>
<h2 id="time-management">Time Management</h2>
<p>I am not strict about your preferred way of time management, but it is important that you have a framework and we follow up with the agreed method. You need to take care of the time management yourself but present your plan and updates, each time we meet. You can as well just use Slack Canvas or written text. But if you want some flaivour, here are some recommendations of the systems that I personally have used and liked:</p>
<ul>
<li>(<em>Recommended</em>) <a href="https://www.notion.so/">Notion</a>(With free <a href="https://www.notion.so/product/notion-for-education">student subscription</a>).</li>
<li>(Recommended) <a href="https://todo.microsoft.com/tasks/">Microsoft To Do</a></li>
<li>Other platforms:
<ul>
<li><a href="https://clickup.com/">ClickUp</a></li>
<li><a href="https://trello.com/">Trello</a></li>
<li><a href="https://todoist.com/">Todoist</a></li>
<li><a href="https://mail.google.com/tasks/canvas">Google Tasks</a></li>
</ul>
</li>
</ul>
<h2 id="literature">Literature</h2>
<h3 id="search--review">Search &#x26; Review</h3>
<p>During your project with me, you will learn about how to search for literature and find relevant studies to shape your project in a proper academic way. We will discuss the techniques all together but before hand you can familiarize yourself with the following platforms:</p>
<blockquote class="prompt-info">
<p>If you are KTH student, review the KTH Library information about <a href="https://www.kth.se/en/biblioteket/soka-vardera">Literature search</a>.</p>
</blockquote>
<p>Here is a list of platforms to use for literature search and review:</p>
<ul>
<li>Search
<ul>
<li><a href="https://scholar.google.com/">Google Scholar</a></li>
<li><a href="https://www.scopus.com/">Scopus</a></li>
<li><a href="https://www.webofscience.com/">Web of Science</a></li>
</ul>
</li>
<li>Evaluate
<ul>
<li><a href="https://elicit.org/">Elicit</a></li>
<li><a href="https://scite.ai/">Scite</a></li>
</ul>
</li>
</ul>
<h3 id="reference-management">Reference Management</h3>
<p>You will need a way to keep track of the references and literature that you find so that later you can easily cite them. There are some softwares that can do that. You can find information about many of them on <a href="https://www.kth.se/en/biblioteket/skriva-referera/referenshanteringsprogram-1.856567">this page</a> of KTH Library. My preffered software is <a href="https://www.zotero.org/">Zotero</a>.</p>
<h4 id="zotero">Zotero</h4>
<ol>
<li>Install Zotero on your computer and browser</li>
<li>Create an account on Zotero</li>
<li>Create a group for your degree project/thesis, and add me as a member using my KTH email</li>
</ol>
<h2 id="writing">Writing</h2>
<h3 id="latex-on-overleaf">LaTeX, on Overleaf</h3>
<p>I recommend you to use LaTeX for writing your thesis and personally I am most comfortable with LaTeX for collaboration and commenting on your writings. For this purpose follow these steps:</p>
<ol>
<li>Go to <a href="https://www.overleaf.com/">Overleaf</a>. Sign in with your KTH account (SSO)</li>
<li>Create a project and add me as a collaborator using my KTH email</li>
<li>Go to the setting of your profile and connect your Overleaf account to your GitHub and Zotero accounts (included in the Overleaf premium with your KTH account)</li>
</ol>
<p>Overleaf is pretty straight forward, but if you do not know LaTeX, the pages below provide very nice and quick tutorials:</p>
<ul>
<li><a href="https://www.overleaf.com/learn/latex/Learn_LaTeX_in_30_minutes"><strong>Learn LaTeX in 30 minutes</strong></a>: Quick option</li>
<li><a href="https://www.learnlatex.org/"><strong>Learn LaTeX</strong></a>: More comprehensive option</li>
</ul>
<p>Apart from these there is a ton of resources online. Just google it!</p>
<h2 id="facilities-for-my-students">Facilities for My Students</h2>
<p>As long as you work with me I could try to provide you with the following facilities:</p>
<h3 id="computational-resources">Computational Resources</h3>
<p>I can give you SSH access to my server for the duration of your project to exclusively be used for your processes. The server configuration is as follows:</p>
<p>| OS | Ubuntu <code>22.04</code> LTS |
| CPU | Intel(R) Core(TM) <code>i9-10850K</code> @ <code>3.60GHz</code> |
| GPU | GeForce RTX 3090, <code>24GB</code> |
| RAM | DDR4 <code>128GB</code> |
| Storage | <code>1TB</code> SSD, <code>4TB</code> HDD |</p>
<p>If you need heavy computation in your project send me your SSH public key, mentioning your needs and demands, and I will give you access to the server.</p>
<blockquote class="prompt-info">
<p>If you are not familiar with SSH, you can find a tutorial in <a href="/posts/SSH-tutorial/">this post</a>.</p>
</blockquote>
<h3 id="office-space-and-access-to-tmh">Office Space and Access to TMH</h3>
<p>If you need it, I can provide you with office space within TMH division. This is not promised and depends on the availability of the space.</p>
<blockquote class="prompt-info">
<p>To get access to TMH facilities, send me your Personal Number (Personnummer) (or birthdate if you do not have a Swedish personal number.).</p>
</blockquote>
<h3 id="computer">Computer</h3>
<p>Depending on what you need to do, I might be able to get you a laptop for the duration of your project. This is not promised and depends on the availability of the laptops.</p>]]></content></entry></feed>