<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Blog -- mari.zip</title>
        <link>https://mari.zip/blog</link>
        <description>strangely quiet here without you</description>
        <lastBuildDate>Thu, 16 Apr 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <atom:link href="https://mari.zip/feed/rss.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Call for Rust 2020]]></title>
            <link>https://mari.zip/blog/call-for-rust-2020</link>
            <guid isPermaLink="false">call-for-rust-2020</guid>
            <pubDate>Mon, 11 Nov 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[The Rust Team wants community voices for Rust 2020. Let's `.unwrap()` my opinion regarding it.]]></description>
            <content:encoded><![CDATA[


Rust is a programming language I genuinly love. Seeing so much community involvement in a language which has great
principles such as great performance and guaranteed memory-safety - right at compile time - is amazing and refreshing.
So after having found out that [the Rust team asked for opinions on Rust 2020](https://blog.rust-lang.org/2019/10/29/A-call-for-blogs-2020.html),
I saw my opportunity to take part in this community and maybe even shape the future of Rust.

## Scratching the bottom of the barrel

Having used Rust in only [one public project](https://github.com/mellowagain/kyo-rs), I am somewhat of a newbie. Still,
I have some wishes for Rust in 2020 and maybe even beyond:

* [Newcomer Accessability](#newcomer-accessability)
* [Improved Compile times](#improved-compile-times)
* [More mature ecosystem](#more-mature-ecosystem)

## Newcomer Accessability

Rust is a weird language. Coming from a background in Java and C++, I've struggled in Rust at first, fighting the compiler
on almost every possible occasion. Within my friend circle I've also noticed some of my friends struggeling in picking
up Rust and wrapping their heads around some unique principles like Borrowing and Lifetimes.

What I wish for Rust in 2020 is improved accessability for newcomers. The Rust book is great but if I'm honest, not
something I could read with much understanding. Sometimes it just becomes too technical or oversimplifies.

The ways people learn languages is very different so I think we should have a few different tutorials and guides
in how to pick up the language. Rust has the perfect community for something like this.

## Improved Compile times

Sometimes after working on my Rust project for some time, the compiler decides to recompile all crates. Why does this happen?
I'd love if Rust would have a explanation why this would happen (for example: Updated dependency x, recompiling everything dependent upon it)

Anyhow, there has already been huge work regarding improving compile times and this is great. I wish for Rust to continue
to improve this for 2020 and beyond.

## More mature ecosystem

I know this is more of a wish for the Rust ecosystem than Rust itself but I still think it has a valid place here. The whole
Rust ecosystem seems kinda, young? Looking on [crates.io](https://crates.io/), many crates have not yet reached the maturity version
of `1.0.0` and higher. I wish that more crates would put maturity on their roadmaps in the near future.

But maybe it's also naive to think that crates should reach maturity. I like to think that Rust itself is a mature language
but some people disagree - thus also eliminating the wish for reaching maturity. I'd love to hear the takes of other people in the
community on this (maybe) issue.

## Wrapping up

Overall I don't have much for Rust. It is already a great language and loved by many people in the world, including me. I have faith
and trust in the community for continuing to improve the language. Rust 2018 was a great improvement when it came out and I can't
wait to see what Rust 2021 will bring with it.


]]></content:encoded>
            <author>Mari (mellowagain)</author>
        </item>
        <item>
            <title><![CDATA[Great things of 2019]]></title>
            <link>https://mari.zip/blog/great-things-of-2019</link>
            <guid isPermaLink="false">great-things-of-2019</guid>
            <pubDate>Sun, 12 Jan 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[The best stuff that I discovered, read, watched etc and more in 2019.]]></description>
            <content:encoded><![CDATA[


The best of 2019 that I discovered, loved and kept close to me. This blog post is inspired by [fogus: The Best Things and Stuff of 2019](http://blog.fogus.me/2019/12/30/the-best-things-and-stuff-of-2019/). Everything is in no particular order.

## Great blog posts read

* [We Need Chrome No More](https://redalemeden.com/blog/2019/we-need-chrome-no-more)
* [Public hacker test on Swiss Post’s e-voting system](https://www.evoting-blog.ch/en/pages/2019/public-hacker-test-on-swiss-post-s-e-voting-system)
* [List of stories set in a future now past](https://en.wikipedia.org/wiki/List_of_stories_set_in_a_future_now_past)
* [I interviewed at six top companies in Silicon Valley in six days](https://blog.usejournal.com/i-interviewed-at-six-top-companies-in-silicon-valley-in-six-days-and-stumbled-into-six-job-offers-fe9cc7bbc996)
* [Most of What We Read on the Internet is Written by Insane People](https://www.reddit.com/r/slatestarcodex/comments/9rvroo/most_of_what_you_read_on_the_internet_is_written/)
* [Let’s stop copying C (2016)](https://eev.ee/blog/2016/12/01/lets-stop-copying-c/)

## Great articles read

* [How to not be alone (2013)](https://www.nytimes.com/2013/06/09/opinion/sunday/how-not-to-be-alone.html)
* [Coders Programming Themselves Out of a Job (2018)](https://www.theatlantic.com/technology/archive/2018/10/agents-of-automation/568795/)
* [A Sleeping Disorder That Turns Life into a Waking Dream](https://www.nytimes.com/2019/10/02/magazine/mysterious-sleeping-disorder-diagnosis.html)
* [SIM swap horror story: I've lost decades of data and Google won't help](https://www.zdnet.com/article/sim-swap-horror-story-ive-lost-decades-of-data-and-google-wont-lift-a-finger/)
* [Living in Switzerland ruined me for America and its lousy work culture (2016)](https://www.vox.com/2015/7/21/8974435/switzerland-work-life-balance)
* [The wave of unicorn IPOs](https://www.economist.com/briefing/2019/04/17/the-wave-of-unicorn-ipos-reveals-silicon-valleys-groupthink)
* [Your digital identity has three layers, and you can only protect one of them](https://qz.com/1525661/your-digital-identity-has-three-layers-and-you-can-only-protect-one-of-them/)

## Favorite podcasts listened to

2019 was the year I started listening to podcasts actively. I regret not having done that much earlier, when I first found out about them.
Well in my defense, I only subscribed to Spotify Premium this year (even thought it's not the only way to listen to these!)

* [Startup](https://gimletmedia.com/shows/startup) - *I loved the episodes about Gimlet, the company that created this podcast. It is a genuine great and emotional adventure about the journey of creating a startup and I enjoyed every second of it. I binged all episodes about Gimlet in less than a month.*
* [Reply All](https://gimletmedia.com/shows/reply-all) - *I found out about this podcast from Waveform (the one below) and the stories told are seriously great.*
* [Waveform](https://open.spotify.com/show/6o81QuW22s5m2nfcXWjucc) - *In-depth discussions about the latest tech from MKBHD, the largest technology channel on YouTube. Having high expectations when this was announced, I was not disappointed when I actually listened to it.*

## Favorite musicians discovered

All artists here are in the Lo-Fi genre. It is my favorite music genre and I listen to it almost exclusively, both at home and on my almost daily public transport rides
to work/school.

* [City Girl](https://twitter.com/citygirltime) - *I love that almost every song has a story behind it which completes the City Girl character.*
* [Dontcry](https://open.spotify.com/artist/3vzJueN7TkCtYpz1myVmDU)

## Favorite shows discovered

* [A Place Further Than The Universe](https://anilist.co/anime/99426/A-Place-Further-Than-the-Universe/)
* [Gabriel Dropout](https://anilist.co/anime/21878/Gabriel-DropOut/)
* [Hibike Euphonium](https://anilist.co/anime/20912/Sound-Euphonium/)
* [I Want to Eat Your Pancreas](https://anilist.co/anime/99750/I-Want-to-Eat-Your-Pancreas/)
* [K-ON!](https://anilist.co/anime/5680/KON/)
* [Kaguya-sama: Love is War](https://anilist.co/anime/101921/Kaguyasama-Love-is-War/)
* [The Pet Girl of Sakurasou](https://anilist.co/anime/13759/The-Pet-Girl-of-Sakurasou/)

## Favorite games discovered

* [Muse Dash (Android)](https://play.google.com/store/apps/details?id=com.prpr.musedash&hl=en)
* [Cytus II (Android)](https://play.google.com/store/apps/details?id=com.rayark.cytus2&hl=en)
* [Overwatch (PC)](https://playoverwatch.com/en-us/)
* [Business Tour (PC)](https://store.steampowered.com/app/397900/Business_Tour__Board_Game_with_Online_Multiplayer/)
* [Anxiety: An Interactive Story (Web)](https://ncase.me/anxiety-demo/) - *A interactive game where YOU play as the anxiety. Small demo that I really enjoyed. Looking forward to the actual game!*

## Countries visited

For the first time in:

* Qatar
* United Kingdom

Visited again:

* Germany
* Philippines

## Great tools discovered

Everything from apps, platforms, extensions etc. that I discovered in 2019 and use (almost) daily.

* [Spotify Premium](https://www.spotify.com) - *Unlimited skipping, no-ads and offline listening. Don't know how I survived 2018 with just Spotify free. Streaming is just too convient.*
* [SponsorBlock](https://sponsor.ajay.app/) - *Automatically skips sponsor spots in YouTube videos, don't know how I was able to watch YouTube without this.*
* [Tildes](https://tildes.net/) - *News aggregator like HN but with higher quality comments and posts. If you want an invite, just send me a tweet via Twitter, I got a few invite codes.*
* [Neon](https://www.neon-free.ch/en/) - *Banking startup in Switzerland. Great product and easy to use app, will probably switch to it fully in the future once it IPO'd (or got acquired).*
* [GSMArena](https://www.gsmarena.com/) - *News and information about everything smartphone related - as I'm a tech enthusiast I check it out on the daily.*

## Programming languages I hacked in

* [Rust](https://www.rust-lang.org/)
* [TypeScript](https://www.typescriptlang.org/)
* [Go](https://golang.org/)
* [PHP](https://www.php.net/)

## Tech products I bought

In order of bought starting from the beginning of 2019 until the end.

* [Samsung Galaxy Watch](https://www.samsung.com/global/galaxy/galaxy-watch/) - *Having a smart watch is just too convient and I see why these days so many people in my age have one.*
* [Sony WH-1000XM3](https://www.sony.com/electronics/headband-headphones/wh-1000xm3/buy/wh1000xm3-b) - *Active Noise Cancelling (ANC) headphones really made a huge difference. Suddenly I was actually looking forward to the almost daily public transport rides.*
* [Logitech G Pro](https://www.logitechg.com/en-ch/products/gaming-mice/pro-hero.html) - *My old mouse stopped working after four years of use so this'll hopefully be a worthy successor.*
* [Huawei Matebook 13](https://consumer.huawei.com/en/laptops/matebook-13/) - *Got it at a discount and honestly a great, fast and portable laptop.*
* [Nintendo Switch](https://www.nintendo.com/switch/) - *Wanted one since the beginning of 2019 and was able to get it off on Black Friday. Really cool console which I love for its portability. Finally I can really game on the go.*

## Plans for 2020

* Write a blog post at least once two months.
* Start building a portofolio on GitHub.
* Contribute more to open-source projects.
* Shrink my [Plan to Watch](https://myanimelist.net/animelist/mari3842h?status=6) list.
* Pass my upcoming Cambridge CAE exam in March.
* Pass the four month personal project we have in school in August.
* Stop some coping mechanisms.

So let's start this year with high spirit. See you maybe for the "Great things in 2020" blog post.


]]></content:encoded>
            <author>Mari (mellowagain)</author>
        </item>
        <item>
            <title><![CDATA[Great things of 2020]]></title>
            <link>https://mari.zip/blog/great-things-of-2020</link>
            <guid isPermaLink="false">great-things-of-2020</guid>
            <pubDate>Sun, 31 Jan 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[2020 was not a year most people would call great but that doesn't mean there wasn't great stuff I've discovered, read or watched.]]></description>
            <content:encoded><![CDATA[


A continuation of my post [Great things of 2019](/blog/great-things-of-2019) but for 2020.
I've switched phones in September but forgot to back up my Materialistic saved data, so I lost most cool blog posts & articles I've read.
Thus these two sections may heavily be biased towards stuff that got posted on HN in Q4 of 2020. As always, everything is in no particular order.

## Great blog posts read

* [My GPT-3 Blog Got 26 Thousand Visitors in 2 Weeks](https://liamp.substack.com/p/my-gpt-3-blog-got-26-thousand-visitors)
* [Minecraft's "Pack.png" Seed Reversal Methodology](https://docs.google.com/document/d/1PpZqHWXPLjOsXf_T7uyH4rWuxUMxzBlxvv5gm19P_Z8/edit)
* [How the Minecraft Title Screen Seed was Found (Video)](https://www.youtube.com/watch?v=GaRurhiK-Lk)
* [What is the Value of Browser Diversity?](https://daverupert.com/2020/09/the-value-of-browser-diversity/)
* [How to back up your password manager](https://www.ctrl.blog/entry/password-manager-backup.html)
* [The HTTP headers you don't expect](https://frenxi.com/http-headers-you-dont-expect/)

## Great articles read

* [I had Covid-19, and these are the things nobody tells you](https://www.latimes.com/sports/story/2020-08-12/column-bill-plaschke-covid-19-experience)
* [The Minecraft Institvte of Technology](https://www.technologyreview.com/2020/08/18/1006217/the-minecraft-institvte-of-technology/)
* [Remote Software Developers Earn 22% More Than Non-Remote Developers](https://whoisnnamdi.com/remote-software-developers-earn-more/)
* [Year Without a Summer](https://en.wikipedia.org/wiki/Year_Without_a_Summer) (w/ [HN discussion](https://news.ycombinator.com/item?id=22400480))
* [SoftBank expects $24 billion in losses from Vision Fund, WeWork and OneWeb investments](https://techcrunch.com/2020/04/13/softbank-expects-24-billion-in-losses-from-vision-fund-wework-and-oneweb-investments/)

## Favorite podcasts listened to

* [Anime in America](https://www.crunchyroll.com/animeinamerica/index.html) - *A interesting look at the history of Anime and Manga and how it came to from Japan to the US. Despite living in Europe, some of the stuff that was mentioned seemed all too familiar.*
* [Trash Taste Podcast](https://www.youtube.com/c/TrashTaste) - *A genuinely funny podcast by three anitubers. It features hilarious stories, trash opinions and bad takes and I've loved every minute of it. I've gotten way too many weird looks because I've started laughing out of nowhere in public transport because of this podcast.*

Continued listening to:

* [Reply All](https://gimletmedia.com/shows/reply-all)
* [Waveform](https://open.spotify.com/show/6o81QuW22s5m2nfcXWjucc)

I've commented on these podcasts on last year's post.

## Favorite musicians discovered

While I have discovered many new musicians in 2020, none of them have sticked with me or become a huge part of my music listening. I've mostly used Spotify's recommendation engine.

## Favorite shows discovered

* My Teen Romantic Comedy SNAFU ([S1](https://anilist.co/anime/14813/My-Teen-Romantic-Comedy-SNAFU/), [S2](https://anilist.co/anime/20698/My-Teen-Romantic-Comedy-SNAFU-TOO/), [S3](https://anilist.co/anime/108489/My-Teen-Romantic-Comedy-SNAFU-Climax/)) - *This show came out of nowhere and ended up being my all-time favorite series, with season three even being my highest rated anime of all time (10/10). I've **genuinly** loved every moment of this show. I highly recommend this show, especially because season 3 ends very satisfactory.*
* [Orange](https://anilist.co/anime/21647/Orange/)
* [Just Because!](https://anilist.co/anime/98820/Just-Because/)
* [Carole & Tuesday](https://anilist.co/anime/101281/Carole--Tuesday/)
* [Grand Blue](https://anilist.co/anime/100922/Grand-Blue-Dreaming/) - *This has to be the funniest anime I've ever seen. Highly recommended for having a fun time.*

## Favorite games discovered

* [Animal Crossing: New Horizons (Switch)](https://animal-crossing.com/new-horizons/)
* [Cyberpunk 2077 (PC)](https://www.cyberpunk.net/ch/en/)
* [Half Life Alyx (PC, VR)](https://www.half-life.com/en/alyx)
* [Valorant (PC)](https://playvalorant.com/en-us/)

I haven't discovered many new games in 2020. I've mostly continued playing games I already knew and loved such as Overwatch.

## Countries visited

Because of the COVID-19 pandemic, I was sadly unable to visit any new countries this year. However, I was able to visit again:

* Germany

It was just a day trip, a quick hop over the border basically. No, I did not catch covid (as far as I know).

## Great tools discovered

Everything from apps, platforms, extensions and more that I discovered in 2020 and use (almost) daily.

* [KDEConnect](https://kdeconnect.kde.org/) / [GSConnect](https://extensions.gnome.org/extension/1319/gsconnect/) / [Your Phone](https://www.microsoft.com/en-us/p/Your-phone/9nmpj99vjbwv?activetab=pivot:overviewtab) - *I spend most of my screen time in front of my computer but I still want to receive notifications and interact with mobile apps from my desktop. These three apps (two for Linux and one for Windows) allow me to do that and it works surprisingly good.*
* [Microsoft Todo](https://todo.microsoft.com/) - *I'm trying to organize my life a little bit better and this has helped immensely. My Samsung Reminders app automatically syncs to it.*
* [Neat URL](https://addons.mozilla.org/en-US/firefox/addon/neat-url/) - *I love sharing links with other people but ever since the introduction of Google Analytics many urls are poised with useless arguments such as `utm_source`. This extension gets rid of them.*
* [Nebula](https://watchnebula.com/) - *Nebula is a independent streaming site which hosts videos from my favorite YouTubers such as Wendover Productions and TechAltar. It also contains great exclusive series and documentaries. It is very cheap and supports your favorite creators directly, so I can highly recommend giving it a shot.*
* [Patreon](https://patreon.com/) - *I've used Patreon in the past to receive donations for my projects but 2020 was the first year I gave money to someone else on Patreon. I've subscribed to OtakuVs to support the creation of their anime.*
* [Samsung Notes](https://www.samsung.com/global/galaxy/apps/samsung-notes/) - *As I've gotten myself a device from the Note series, I had to use the S-Pen. And damn it's useful, mostly because of the great Samsung Notes app features and syncronization with OneNote.*
* [Webtoons](https://www.webtoons.com/en/) - *I've discovered the world of Webtoons. You can imagine this to be some sort of modern version of Manga, optimized for reading on smartphones. I recommend True Beauty.*
* [Windows Terminal](https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab) - *Finally a useable terminal on Windows.*

This list does not include tools that aren't exciting, such as Microsoft Teams which I used extensively in online school while there was a lockdown.

## Programming languages I hacked in

I didn't learn any new programming languages in 2020. I've focused more on frameworks such as Pyramid (Python) and actix (Rust).

## Tech products I bought

* [Samsung LC24RG50FQUXEN](https://www.samsung.com/uk/business/monitors/monitor-crg50/lc24rg50fquxen/) (February) - *Great value curved 144hz monitor. It has become my main monitor and joined my triple monitor setup.*
* [SteelSeries Arctis 7 Wireless](https://steelseries.com/gaming-headsets/arctis-7) (April) - *God I hate wires! After having yet another headset break on me, I've decided to actually spend a triple digit amount of money to buy an actual good headset and I'm not regretting it. It has held up pretty well already and being able to walk around the apartment while gaming or listening to online school lessons is so convenient.*
* [HyperX Fury 32 GB 3200Mhz DDR4 RAM](https://www.hyperxgaming.com/us/memory/fury-ddr4-rgb) (June) - *At the start of the year I've found that I've been hitting my 16 GB limit on my machine pretty often with all programs and games I have constantly open. The logical step was to upgrade and when digitec had a sale in June this was perfect. RAM prices really have come down since I've built my pc and I was able to buy this 32 GB kit for the price of the 16 GB kit I had in my pc since I built it in 2017.*
* [Samsung Galaxy Note20 Ultra 5G](https://www.samsung.com/us/smartphones/galaxy-note20-5g/) (August) - *I upgrade my phone every two years, primarily because the battery wears out. I've stayed with Samsung as a phone brand as I've already bought into their ecosystem with my Galaxy Watch & Buds. Seeing the camera issues that happened with the S20 Ultra in february I couldn't allow myself to buy a phone with these issues so it had to be the newest flagshig from the Note line. I've since really grown to the pen on the phone and I use it pretty often in school.*
* [WD Black SN750 1 TB NVMe SSD](https://shop.westerndigital.com/products/internal-drives/wd-black-sn750-nvme-ssd#WDS100T3X0C) (November) - *My 250GB SSD has become full so I had to upgrade. Thanks to a great black friday deal on Amazon, I even got myself an NVMe one.*
* [HyperX Alloy Origins](https://www.hyperxgaming.com/us/keyboards/alloy-origins-mechanical-gaming-keyboard) (November) - *Since the start of the year I've had problems with sometimes double typing keys on my CoolerMaster Masterkeys L. I've already cleaned it and it didn't help so it was time to replace it. Black friday at Media Markt got me covered with a nice mechanical keyboard. I've found these HyperX red switches to be very much the same as the CherryMX Reds I had on the Coolermaster.*
* [Logitech G Pro X Superlight Wireless](https://www.logitechg.com/en-us/products/gaming-mice/pro-x-superlight-wireless-mouse.html) (December) - *As already mentioned above, I've bought into the wireless hype. I was eyeing the Logitech G Pro Wireless since a few months already and when I wanted to buy it on Black Friday it wasn't discounted. Thus I've decided to spend the additional money to get the newest product of Logitech, the Superlight variant of the G Pro Wireless.*
* [Dream Machine DM Pad XL](https://www.dreammachines.io/en/dmpadxl) (December) - *With a new mouse we also need a new mouse pad, right? On the long term I'm planning to replace this with a Artisan mousepad so it'll probably not stay for very long.*

A few comments about the tech I bought in 2019:

* Buying a [Samsung Galaxy Watch](https://www.samsung.com/global/galaxy/galaxy-watch/) in 2019 might've been one of the best decisions I could've made. Once COVID-19 took over our lives, it was recommended not to touch surfaces because of fears of catching the virus. My smartwatch allowed me to see notifications directly on my wrist without having to take out my phone and touch it.
* Noise Cancellation of the [Sony WH-1000XM3](https://www.sony.com/electronics/headband-headphones/wh-1000xm3/buy/wh1000xm3-b) got worse after multiple updates (or maybe use?). I'm planning on replacing the ear cups to see if that makes a difference.
* Despite a lockdown and home schooling, I wasn't able to use my [Nintendo Switch](https://www.nintendo.com/switch/) as much as I would've loved to.

## Plans from 2020

In last years' article I wrote down a few plans I had. I sadly wasn't able to complete all of them:

| Goal                                                              | Achieved | Comment                                                                                                                                     |
|-------------------------------------------------------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------|
| Write a blog post at least once two months.                       | No       | In fact, the only post in 2020 was the Great things of 2019 article. It is easy to blame the pandemic but I know it was just me being lazy. |
| Start building a portofolio on GitHub.                            | Yes      | A little bit, but not completely.                                                                                                           |
| Contribute more to open-source projects.                          | Yes      | I completed Hacktoberfest 2020 for the first time.                                                                                          |
| Shrink my Plan to Watch list.                                     | No       | It grew even more. I'm now at 126 shows (at the time of writing).                                                                           |
| Pass my upcoming Cambridge CAE exam in March.                     | Yes      | Passed with Grade B                                                                                                                         |
| Pass the four month personal project we have in school in August. | Yes      | Passed with 4.5                                                                                                                             |
| Stop some coping mechanisms.                                      | No       |                                                                                                                                             |

That is 4 out 7 goals achieved or a 57.14% success rate.

## Plans for 2021

In addition of trying to complete last years' goals, I'd like to:

* Pass ending exams for my apprenticeship
* Get a new job when my contract ends in August
* Get my drivers license
* Get into investing and the stock market


]]></content:encoded>
            <author>Mari (mellowagain)</author>
        </item>
        <item>
            <title><![CDATA[Isolated development environments with litterbox]]></title>
            <link>https://mari.zip/blog/isolated-dev-environments</link>
            <guid isPermaLink="false">isolated-dev-environments</guid>
            <pubDate>Sun, 22 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[After a recent string of supply chain attacks, it was time to isolate my development environments]]></description>
            <content:encoded><![CDATA[


The past few months have not been the best for developers. There has been too many supply chain attacks, targeting not
just the NPM ecosystem but also the Cargo ecosystem as well as GitHub actions:

- [The Shai-Hulud 2.0 npm worm](https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/)
- [GitLab discovers widespread npm supply chain attack](https://about.gitlab.com/blog/gitlab-discovers-widespread-npm-supply-chain-attack/)
- [Malicious Rust Packages Hit crates.io](https://www.abhs.in/blog/rust-crates-io-supply-chain-attack-developer-credentials-2026)
- [Ghostaction: 3,325 Secrets Stolen Through Compromised GitHub Workflows](https://blog.gitguardian.com/ghostaction-campaign-3-325-secrets-stolen/)

This recent uptick of attacks and self-propagating worms is scary, and it means we have to start taking security more
seriously as developers. I have looked around and found [`litterbox`](https://litterbox.work/), a Linux sandbox environment
catered to the needs of developers. While it is in early stage, I decided to give it a try and it was surprisingly easy.

## What litterbox is and what it isn't

Before using any tool, it's good to get a sense of what it does and what it doesn't. Notably, Litterbox is not a full
virtual machine, instead running inside of rootless Podman containers with only access to a dedicated home folder
(located in `~/Litterbox/homes/<container name>`) and nothing above it. It also features a special SSH agent, showing a
GUI prompt every time a program wants to use your SSH key. See the appendix the end of the article for a screenshot of that.

More importantly, it is **not a virtual machine**. This means that all programs still run on your original OS' kernel and
your native Wayland server. This is especially bad because having access to the Wayland server means also having access
to your global clipboard, a limitation that you sadly are not able to work around (for now, I hope).

Of course if there is an exploit in the Linux kernel or anything that is exposed to the Litterbox (including Wayland and
any devices you explicitly attached with `litterbox devices`), that can then also be exploited. But recent supply chain attacks have
mostly been trying to get your credentials to stuff like Git, NPM, crates.io etc. so this provides a good shield
against that. Read all about the limitations of Litterbox on its [README](https://github.com/Gerharddc/litterbox?tab=readme-ov-file#isolation-limitations).

## My development environment

So let's get ready to set up a Litterbox. I have decided to have **one litterbox per project**. This gives the best
isolation between projects but at the expense of disk space, as all runtimes, dependencies and IDE's need to be
installed in every litterbox separately. That is a trade-off I am willing to make for the sake of security. You can
choose to instead define a litterbox per-language or however you see fit.

I'm going to set up a container for this very website, [mari.zip](https://github.com/mellowagain/website) so we need:

* `nodejs`, as my project is a Next.js app
* `pnpm`, the projects default package manager
* `WebStorm`, the JetBrains IDE of choice for Node web development
* A new ssh key for the litterbox

This list is different per-project, for example for [GitArena](https://github.com/mellowagain/gitarena) I installed `cargo`
and `RustRover` instead.

## Installing litterbox

Installing it is as simple as running:

```bash
curl -fsSL https://litterbox.work/install.sh | sh
```

This will install the latest litterbox version **for your local user**, in my case `litterbox 0.3.2`. Explicitly not
system-wide, as it should be. Of course, you can critique the old curl and then pipe into bash, but if you're like that
it seems that litterbox is easy to compile by yourself, being fully written in Rust.

## Creating the litterbox

Creating the litterbox is a simple two-step progress, first defining it and then building the container. For the
name I have chosen marizip to represent the project that is inside of it.

```bash
litterbox define marizip
```

It will then ask you for a template, I picked `CachyOS` becaue my main system is Arch so the commands are similiar enough
to not get mixed up between main system and container. There is an argument to be had to explicitly use a different distro
for your container to always be sure you're running commands in the correct environment, but I decided against it.

Next up we need to build the litterbox:

```bash
litterbox build marizip
```

It will prompt you to set a user password. I have Bitwarden as my password manager, so I generate a new, unique password
for all of my litterboxes.

Afterwards it will ask you a lot of questions, these are **very important** to consider as after they have been defined
you cannot change them and would have to rebuild your litterbox if you really wanted to.

## The questions

### Network mode

```text
? Choose the network mode for this Litterbox:
> Pasta (isolated user-mode networking stack)
  Pasta with automatic port forwarding (host to container)
  Pasta with automatic port forwarding (container to host)
  Pasta with automatic port forwarding (bidirectional)
  Host networking (i.e. NO ISOLATION)
```

This should be self explaining. As mari.zip is a web app, I often use `pnpm run dev` to quickly spin up a dev server
to see changes immediately, so I chose `Pasta with automatic port forwarding (container to host)`. Depending on your
applications, you should choose differently. **Do not choose the last option, unless you have good reason to.**

### CAP_NET_RAW

```text
? Do you want to support `ping` inside this Litterbox? (y/N)
[This will enable `CAP_NET_RAW`.]
```

If you're around the Kubernetes or devops world, you probably [already know of this](https://kyverno.io/policies/best-practices/require-drop-cap-net-raw/require-drop-cap-net-raw/).
`CAP_NET_RAW` enables applications to craft and send arbitrary network packets, as used by tools like `ping` and `nmap`
as well as binding to any network address regardless of ownership and intercepting traffic on the network interface.
**Unless you have a specific need for it, do not enable it.**

### CAP_NET_ADMIN

```text
? Do you want to support TUN/TAP creation inside this Litterbox? (y/N)
[This will enable `CAP_NET_ADMIN` and expose `/dev/net/tun`.]
```

`CAP_NET_ADMIN` is the equivalent of granting root access to network, allowing programs to bring interfaces up and down,
assigning IP addresses, modifying the routing table, modifying iptables rules and creating and configuring network namespaces.
This is mostly useful if you'd like to run an iptables firewall or a VPN daemon inside the litterbox. **Again, unless you
have a specific need for it, do not enable it.**

### Packet forwarding

```text
? Do you want to enable packet forwarding inside this Litterbox? (y/N)
```

Packet forwarding allows programs within the litterbox to act as packet routers, routing packets from one interface
to another. This is useful if you're running a VPN server or a proxy within the container. This is **not** however
needed for my use case where I just want to visit the local dev server from my main machines browser outside the container.
This is just for routing traffic _between_ network interfaces. **Again, unless you have a specific need for it, do not enable it.**

### User groups

```text
? Do you want to keep your user groups inside this Litterbox? (y/N)
[This will preserve your host user's group memberships.]
```

In Linux a lot of access is managed through groups, for example `docker` (for rootless docker) or `root` (for running `sudo`).
I found this to only really useful if you're passing in `litterbox devices` which are bound to a specific group. **It is most
cleanly to not enable it but for your use case it might be required.** For my normal web development however, it isn't.

### seccomp confinement

```text
? Do you want to disable seccomp confinement? (y/N) $
[This enables 'dangerous' syscalls required by things like the Mojo debugger.]
```

Seccomp stands for Secure Computing Mode and is a kernel feature to filter syscalls programs can call. Confinement restricts
them to be the normal syscalls most programs use, but for some special ones like debuggers which use `ptrace`, you
would need to enable it. **Enable this if your programs need it.**

### Pipewire

```text
? Do you want to expose PipeWire inside this Litterbox? (y/N)
[This will allow audio applications to work inside the Litterbox.]
```

This one is relatively simple. Do you need audio in your container like speaker output or microphone input? If yes,
go ahead and enable it but for my use case I do not need it.

### SHM size

```text
? Shared memory size in GB (leave empty for default): ()
[Sets --shm-size for the container (e.g., 8 for 8G).]
```

Setting a big enough shared memory size is essential for programs using IPC, such as for example web browsers or in my
case JetBrains IDE's such as WebStorm. I set it to 4 GB for mine, but depending on your setup you might want to choose
a different size.

## Installing dependencies

Now the litterbox should be successfully built we need to go ahead and install our projects required dependencies. First
we need to attach to a terminal within the container:

```bash
litterbox enter marizip
```

First we should update all packages in our system:

```bash
paru -Syu
```

and then for the project itself we just need Node.js and pnpm, you should adjust for the dependencies required for your project:

```bash
paru -S nodejs npm
sudo npm install --global corepack@latest
corepack enable pnpm
```

and for Webstorm we need to install some additional packages, as described in my [Installing JetBrains IDE in litterbox](https://github.com/Gerharddc/litterbox/discussions/63) post:

```bash
paru -S webstorm webstorm-jre freetype2 ttf-dejavu fontconfig libxkbcommon libxkbcommon-x11
fc-cache -fv
```

If you want to render the Markdown preview in the JetBrains IDE additionally install:

```bash
paru -S alsa-lib pango libxrandr libxdamage libxcomposite libcups at-spi2-core nss
```

Then we can launch WebStorm for the first time within the container with a forced override to use Wayland:

```bash
_JAVA_OPTIONS="-Dawt.toolkit.name=WLToolkit" webstorm
```

Webstorm will warn us that we used the `_JAVA_OPTIONS` override, so we should persist the forced usage of Wayland the right way.
We do this by clicking on the Settings cog and then `Edit Custom VM options` and adding the argument into the newly opened file/window:

```text
-Dawt.toolkit.name=WLToolkit
```

From now on we can just start it within the container by typing `webstorm`, no need to set the `_JAVA_OPTIONS` env variable first.

## Setting up ssh keys

As said, I like to have a separate SSH key for every litterbox. I chose `marizip` for the SSH key name, but you can choose whatever,
it **doesn't** have to be the same as the container name. **The password it prompts for is for the SSH key storage, not the container**:

```bash
litterbox keys generate marizip
litterbox keys attach marizip marizip
```

You might have to restart your litterbox once or twice to have the new key be correctly attached to it. Litterbox stops
the container automatically when all windows to it all closed.

Now to allow cloning and pushing from GitHub, I add the SSH key as a **project specific** [deploy key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys#deploy-keys)
so it's scoped to only the project that is actually running inside the Litterbox. First we need to get our public key:

```bash
litterbox keys print marizip
```

and then we can add it to our GitHub project by going to the repo → Settings → Deploy Keys and then adding it as a read
and write deploy key.

Having keys attached means that everytime you `litterbox enter` to a litterbox, you will need to enter your SSH key storage password.

## Adding to launcher

To be able to launch the IDE easier, I add it to my system launcher. As litterbox requests your SSH key store password, we need to have
an interactive script to input it when required. I generated this quick Python script with Claude to do that, the only required dependency
is `pexpect` (on Arch: `sudo pacman -S python-pexpect`). Be sure to adjust the path to your own username:

```python
#!/usr/bin/env python3
import pexpect
import sys
import os

name     = sys.argv[1]
ide      = sys.argv[2]
password = os.environ['LITTERBOX_PASSWORD']

child = pexpect.spawn(f'/home/mari/.local/bin/litterbox enter {name} {ide}', timeout=60)
child.expect('password')
child.sendline(password)
child.expect(pexpect.EOF, timeout=None)
```

It takes the name of the container as the first argument and the launch command for the IDE as the second.
The password gets pulled from the `LITTERBOX_PASSWORD` environment variable, which I set globally for my system.

Then we can create a `.desktop` file in a folder our launcher looks for, in my example `~/.local/share/applications/`
(find out with `printenv XDG_DATA_DIRS`):

```ini
[Desktop Entry]
Name=WebStorm (marizip)
Comment=Webstorm for maridotzip Project
Exec=/home/mari/.local/bin/litterbox-jb.py "marizip" "webstorm"
Icon=webstorm
Terminal=false
Type=Application
Categories=Development;IDE;
StartupWMClass=jetbrains-webstorm
```

and to apply the changes we just need to refresh our desktop database:

```bash
update-desktop-database ~/.local/share/applications
```

## Conclusion

We now have an isolated development environment setup. In case one of our dependencies do end up shipping malware:

1. It only affects the container we are in
2. The only secrets that can be stolen are the ones we store in our environment, which in the ideal case should be none or just development credentials with weak permissions.
3. Our SSH key cannot be used to further spread the malware as our SSH agent popup would make us suspicious.

Finally, we can code in peace. Time for the exciting stuff.

## Appendix: Litterbox SSH request popup

![Litterbox SSH request popup](/images/blog/dev-envs/ssh-request.png)


]]></content:encoded>
            <author>Mari (mellowagain)</author>
        </item>
        <item>
            <title><![CDATA[Reverse Engineering a Protocol Impossible to Reverse Engineer]]></title>
            <link>https://mari.zip/blog/reverse-engineering-a-protocol-impossible-to-reverse-engineer</link>
            <guid isPermaLink="false">reverse-engineering-a-protocol-impossible-to-reverse-engineer</guid>
            <pubDate>Sun, 21 Oct 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[A overview of how the osu! client and the osu!Bancho server communicate with each other]]></description>
            <content:encoded><![CDATA[


[Ripple][0], a 3rd party server for the video game [osu!][1], had the following sentences
on their landing page since literally forever:

> ~~reverse engineering a protocol impossible to reverse engineer since always~~
> we are actually reverse engineering bancho successfully. for the third time.

But how much truth is behind these sentences? In this article I will give a quick
overview in how the osu! client and the osu!Bancho server communicate with each other
and how I've gone ahead and figured these things out.

## Sniffing the traffic between client and server

So let's start by opening up Wireshark and just capturing a few packets. You'll notice
quickly that the communication between the osu! client and the osu!Bancho server happens
using simple HTTP requests.

![Wireshark](/images/blog/osu-re/wireshark.png)

Normally, these would be sent over HTTPS, but I've gone ahead and patched my client
to connect to osu!Bancho servers without HTTPS. If you want to decrypt the original
HTTPS traffic, just search up ways to decrypt HTTPS traffic in Wireshark.

## So much traffic today!

Immediately we notice that osu! seems to send a few checks to `/web/` routes, the first one
seems to check if my client is up-to-date, as you can see from the parameters it sends.

Next up osu! sends a request to `/web/bancho_connect.php`. Now this is interesting. This
seems to be a pre-connection mechanism by osu! for eventual ban checking or something. It just
seems to return the registration country if supplied with correct parameters. Because this
query contains the md5sum of my password and my unique client hash, I've censored parts of it.

We also see a few POST requests to `/web/osu_error.php`. osu! automatically sends the whole
client information to that endpoint in case a error occurs, and because a few routes returned
404 (because I conveniently null-routed them) - that shows up a few times.

## Authentication

But now lets get to the actual interesting part. osu! sends a POST request to the `/` endpoint.
Looking at the body sent, it seems to be login and client information. This is the request
that authenticates us with the osu!Bancho server. The body is in the following format:

```plaintext
username
md5sum of the password
Version|UTC offset|Display full location|Colon seperated list of MAC addresses which are MD5 hashed|Block non-friend PMs

```

Funnily enough, because I'm running osu! on my Linux machine under Wine, the colon separated
list of MAC addresses contained a string which wasn't md5 hashed, it's value was `runningunderwine`.

Now let's take a look at what the server responded and...

![Response](/images/blog/osu-re/response.png)

What the hell? Until now everything was nice and plain text and now we got some garbage data
with some strings between them? This doesn't seem right - well, actually, it does. We'll
be taking a look at them in the next section. Let's first address the headers that we see
because this is the first time the server set some headers on the response which seem interesting.

| Header         | Description                                                                                                                        |
|----------------|------------------------------------------------------------------------------------------------------------------------------------|
| `cho-protocol` | This is the version of the cho-protocol used in this response. The newest version known as of the writing of this article is `19`. |
| `cho-token`    | This is the authentication token used for future requests. Think of it like a session cookie.                                      |
| `cho-server`   | **This is a non-standard header**. It was set by this 3rd party server implementation for identification of the software.          |

Now that this is out of the way, let's take a look at the seemingly random data mixed with strings
between them. This data is actually a array of cho packets. But how exactly is the format of one
cho packet?

## Disassembling one packet

Let's take a look at one packet sent from the server to the client:

```hex
18 00 00 0F 00 00 00 0B 0D 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21
```

Looks pretty cryptic, doesn't it? But it isn't actually that hard. A cho packet has always
a seven byte header and the actual packet data after it. It is in the following format:

| Size    | Description      | Type                                                               |
|---------|------------------|--------------------------------------------------------------------|
| 2 bytes | Packet ID        | LE 16-bit Integer                                                  |
| 1 byte  | Null byte        | Backwards compatibility with the 2009 osu! client, no longer used. |
| 4 bytes | Packet Data Size | LE 32-bit Integer                                                  |

The remaining bytes after this header are all part of the actual packet body.

Using Python's `struct` module, we can easily translate the bytes above into human readable
data.

```python
>>> struct.unpack("<h", b"\x18\x00")[0]          # Packet ID
24
>>> struct.unpack("<i", b"\x0F\x00\x00\x00")[0]  # Packet Data Size
15
```

Great. As we can see the packet ID for our packet is `24`. I've compiled a list of known packets
that you can find [here][2]. The packets prefixed with `in` are sent by the osu! client and the packets
prefixed with `out` are sent by the osu!Bancho server. Looking at the list, it seems we have
a announcement packet here.

```cpp
out_announce = 24,
```

and sending this exact packet to our osu! client confirms our thesis:

![osu! Ingame](/images/blog/osu-re/osu.png)

We also got `15` for the packet data size and looking at the remaining bytes, they are
exactly 15. Great! Seems we're on a good way already. So let's continue reading the packet
body.

## Parsing the packet body

So let's jump right into it. The first byte we encounter is `0B`. It signalizes that the
following bytes should be interpreted as a non-empty string.

So let's try that, shall we?

```python
>>> b"\x0D\x48\x65\x6C\x6C\x6F\x2C\x20\x77\x6F\x72\x6C\x64\x21".decode("UTF-8")
'\rHello, world!'
```

But what's this? The string at the beginning has a carriage return. Is this actually correct?
Hint: it's not. But what is it then?

After some search on the Internet I encounter the osu! wiki. To be more precise, I encounter
the wiki page for the [`.osr` File Format][3]. A `.osr` file is a encoded osu! replay file
containing all cursor movement and button clicks. Looking at their table of data types,
we can see the following description:

> **String**
> Has three parts; a single byte which will be either 0x00, indicating that the next two parts are not present, or 0x0b (decimal 11), indicating that the next two parts are present. If it is 0x0b, there will then be a ULEB128, representing the byte length of the following string, and then the string itself, encoded in UTF-8.

Could peppy have decided to use the same format for strings in cho packets as well? Let's
try it out.

Based on the description, the byte after the `0B`, which in our case is `0D`, represents
the byte length of the following string. Let's convert this then.

```python
>>> 0x0D
13
```

Wow, what a coincidence! This is exactly the amount of the remaining bytes in our packet body.
Converting the remaining bytes into a UTF-8 string and we get the correct string:

```python
>>> b"\x48\x65\x6C\x6C\x6F\x2C\x20\x77\x6F\x72\x6C\x64\x21".decode("UTF-8")
'Hello, world!'
```

Success! We've successfully interpreted a cho packet containing a string as body. Let's try
interpreting one which doesn't have a string body.

## Don't you reply to me

The same HTTP body also contained another packet:

```hex
05 00 00 04 00 00 00 FF FF FF FF
```

Let's try parsing this. First we get again the packet ID and the packet data size.

```python
>>> struct.unpack("<h", b"\x05\x00")[0]          # Packet ID
5
>>> struct.unpack("<i", b"\x04\x00\x00\x00")[0]  # Packet Data Size
4
```

Looking again on the packet list, the packet seems to be a login reply.

```
out_login_reply = 5,
```

A login reply packet has exactly one argument, the user ID or error code. If the passed argument,
a signed 32-bit integer, is negative, a error occurred. If the argument is positive, it is the
user ID of user you logged into as.

So let's do that.

```python
>>> struct.unpack("<i", b"\xFF\xFF\xFF\xFF")[0]
-1
```

We see that we received a negative number. This indicates a error in the login process. Looking
at the list of errors we see that we sent invalid credentials.

```cpp
enum class login_responses : int32_t {
    invalid_credentials = -1,
    outdated_client = -2,
    user_banned = -3,
    multiaccount_detected = -4,
    server_error = -5,
    cutting_edge_multiplayer = -6,
    account_password_rest = -7,
    verification_required = -8
};
```

So we've also successfully parsed a packet which only contained a 32-bit integer as argument.
That was easy, wasn't it?

## Conclusion

As we've seen from this writeup, the cho protocol is in no means impossible to reverse engineer.
It follows the common principle of [Type-length-value][4], a encoding scheme used for optional
information elements.

I hope this little overview of the cho protocol gave you a better understanding of how
the osu! game client and the osu!Bancho server communicate with each other.

I have written this article to allow for new people to dig a bit deeper into the inner workings
of this beautiful rhythm game. The development community around osu! is amazing and has many
different aspects which may also interest you.

This guide does not apply to the open-source version of osu!, called osu!lazer. The osu!lazer
project uses JSON to communicate with the osu-web server (not osu!Bancho).

## Credits

This guide was created with the help of [czapek][5], a friend of mine with who I wrote a
server side implementation of the cho protocol, Shiro, which was used as osu!Bancho server
throughout this writeup.

Thanks to [Mempler][6] for demystifying a few values in the initial
login request sent by the osu! client.

[0]: https://ripple.moe
[1]: https://osu.ppy.sh
[2]: https://github.com/mellowagain/shiro/blob/master/src/io/layouts/packets.hh
[3]: https://osu.ppy.sh/help/wiki/osu!_File_Formats/Osr_(file_format)
[4]: https://en.wikipedia.org/wiki/Type-length-value
[5]: https://github.com/cyanidee
[6]: https://github.com/Mempler


]]></content:encoded>
            <author>Mari (mellowagain)</author>
        </item>
    </channel>
</rss>