<?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/">
    <channel>
        <title>Morgyn IO</title>
        <link>https://morgyn.io/</link>
        <description>Morgyn IO blog feed</description>
        <lastBuildDate>Mon, 07 Sep 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>vite-plugin-rss</generator>
        <language>en</language>
        <image>
            <title>Morgyn IO</title>
            <url>https://morgyn.io/image.png</url>
            <link>https://morgyn.io/</link>
        </image>
        <copyright>All rights reserved 2026, Morgyn IO</copyright>
        <item>
            <title><![CDATA[TIL: Google Fonts Previews the Universal Declaration of Human Rights]]></title>
            <link>https://morgyn.io/post/google-fonts-human-rights</link>
            <guid isPermaLink="false">https://morgyn.io/post/google-fonts-human-rights</guid>
            <pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Every Google Fonts specimen opens with the same line about freedom of thought and conscience. The sample text is the Universal Declaration of Human Rights — a quiet easter egg most people scroll past.]]></description>
            <content:encoded><![CDATA[<p>Google has always hidden little things in its products. Search "do a barrel roll" and the page rolls. Search "askew" and everything tilts. "Recursion" politely corrects itself to "recursion." "The answer to life the universe and everything" returns 42. Most of these are jokes.</p><p>The one I found this week is not a joke, and I think it is the best one they have done.</p><h2>What I noticed</h2><p>I was on <a href="https://fonts.google.com" target="_blank" rel="noopener noreferrer">Google Fonts</a> picking typefaces for a project, scrolling the endless grid of specimens. After a while I realized every single card was previewing the *same sentence*:</p><p>> Everyone has the right to freedom of thought, conscience and religion; this > right includes freedom to change his religion or belief...</p><p>I assumed it was filler, like "the quick brown fox." A quick search told me otherwise: that is <strong>Article 18 of the Universal Declaration of Human Rights</strong>.</p><h2>It is the whole document</h2><p>Once I clicked into a font to actually download it, the specimen page laid out paragraph after paragraph — and they are all from the Declaration. The page opens on the Preamble:</p><p>> Whereas disregard and contempt for human rights have resulted...</p><p>and then walks through the text. Here is what Google is quietly putting in front of every designer, every day, and where each piece comes from:</p><table><thead><tr><th>Sample text</th><th>Source</th></tr></thead><tbody><tr><td>"Whereas recognition of the inherent dignity..."</td><td>Preamble, opening line</td></tr><tr><td>"Whereas disregard and contempt for human rights have resulted..."</td><td>Preamble</td></tr><tr><td>"No one shall be subjected to arbitrary arrest, detention or exile."</td><td>Article 9</td></tr><tr><td>"Everyone is entitled in full equality to a fair and public hearing by an independent and impartial tribunal, in the determination of his rights and obligations and of any criminal charge against him."</td><td>Article 10</td></tr><tr><td>"No one shall be subjected to arbitrary interference with his privacy, family, home or correspondence, nor to attacks upon his honour and reputation. Everyone has the right to the protection of the law against such interference or attacks."</td><td>Article 12</td></tr><tr><td>"Everyone has the right to freedom of thought, conscience and religion; this right includes freedom to change his religion or belief, and freedom, either alone or in community with others and in public or private, to manifest his religion or belief in teaching, practice, worship and observance."</td><td>Article 18</td></tr><tr><td>"Everyone has the right to freedom of opinion and expression; this right includes freedom to hold opinions without interference and to seek, receive and impart information and ideas through any media and regardless of frontiers."</td><td>Article 19</td></tr><tr><td>"Everyone has the right to rest and leisure, including reasonable limitation of working hours and periodic holidays with pay."</td><td>Article 24</td></tr></tbody></table><p>The full text — Preamble plus 30 articles — is worth reading in full on the UN's site: <a href="https://www.un.org/en/about-us/universal-declaration-of-human-rights" target="_blank" rel="noopener noreferrer">Universal Declaration of Human Rights</a>.</p><h2>Why it is a good choice</h2><p>Specimen text has a job: it needs enough variety of letters, punctuation, capital letters, and word lengths to show how a typeface actually behaves in running text. Lorem ipsum does that but says nothing. Pangrams do it in one line but read as gibberish at paragraph length.</p><p>The Declaration is real prose, in the public domain, translated into more languages than almost any other document on earth — which matters a lot when you are testing fonts that need to render Greek, Cyrillic, Arabic, Devanagari, and CJK. It is practical *and* it means that hundreds of thousands of people setting type for a landing page are, for a second, reading "no one shall be subjected to arbitrary arrest."</p><h2>The point</h2><p>Most easter eggs are there to make you smile. This one is there to make you look, even briefly, at something that matters. I have used Google Fonts for years and never read the words. This week I did. It also is a reminder of the times that we are currently living in and how the rights of many in our country are actively being removed, or at least attempted to using the mindset of "do it and ask for foregiveness later".</p><p>TIL, and now you have too.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>TIL</category>
            <category>Google</category>
            <category>Google Fonts</category>
            <category>easter eggs</category>
            <category>human rights</category>
            <category>typography</category>
            <category>design</category>
        </item>
        <item>
            <title><![CDATA[TIL: ESPN Runs on a Public API It Doesn't Admit Exists]]></title>
            <link>https://morgyn.io/post/espn-hidden-api</link>
            <guid isPermaLink="false">https://morgyn.io/post/espn-hidden-api</guid>
            <pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The JSON endpoints behind ESPN.com and the ESPN app are open, undocumented, and unauthenticated. Developers reverse-engineered the docs ESPN never wrote — and AI is about to send more traffic their way.]]></description>
            <content:encoded><![CDATA[<p>NOTE: The following has been a security risk for ESPN for years and they have done nothing to address it.</p><p>I was poking around for a way to pull live scores into a side project and went looking for ESPN's API. TIL: there isn't one. Or rather, there very much is one, it is just not something ESPN will acknowledge, document, or support.</p><h2>The situation</h2><p>ESPN used to run an official developer program with API keys and terms of service. They shut it down years ago. What they did <strong>not</strong> do is turn off the endpoints that their own website and mobile app call. Every score, every box score, every team page on ESPN.com is a front end talking to a JSON API at hosts like <code>site.api.espn.com</code> and <code>sports.core.api.espn.com</code>.</p><p>Those endpoints are still there. They require no API key, no auth header, no sign-up. If you open your browser dev tools on an ESPN scoreboard page and watch the network tab, you can see them go by, and you can paste the URL straight into another tab and get the JSON back.</p><pre><code># NFL scoreboard
https://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard

# NBA teams
https://site.api.espn.com/apis/site/v2/sports/basketball/nba/teams

# MLB news
https://site.api.espn.com/apis/site/v2/sports/baseball/mlb/news

# English Premier League scoreboard
https://site.api.espn.com/apis/site/v2/sports/soccer/eng.1/scoreboard

# College football scoreboard
https://site.api.espn.com/apis/site/v2/sports/football/college-football/scoreboard
</code></pre><h2>The documentation is entirely community-made</h2><p>Because ESPN publishes nothing, developers reverse-engineered the API the slow way: inspecting the requests the site makes, guessing at path patterns, poking at query parameters, and writing down what came back. The result is a small ecosystem of unofficial docs — the most-shared one is a GitHub Gist by Akshay Easwaran titled "ESPN's Hidden API Endpoints" — plus blog posts, Postman collections, and wrapper libraries in half a dozen languages. None of it is authoritative. It is people comparing notes on someone else's private infrastructure.</p><p>That works surprisingly well, right up until it doesn't. There is no changelog, so fields disappear without warning. There is no status page. There is no rate limit you can read — you just find the wall by hitting it. People have already noticed access getting flakier in 2026 and started passing around workarounds like swapping in a <code>site.web.api.espn.com</code> host.</p><h2>Why I think this gets worse fast</h2><p>Here is the part that actually made me want to write this up. This API has been a quiet open secret for years, used by a relatively small number of people who mostly knew to be careful with it. That is changing.</p><p>AI coding assistants know about these endpoints. Ask one to "build me a live NFL score widget" and there is a good chance it reaches for <code>site.api.espn.com</code>, because that pattern is all over its training data. The barrier to standing up a project that hammers ESPN's servers used to be "know that the API exists and how to find it." Now the barrier is a sentence.</p><p>Multiply that by every person vibe coding a fantasy tool, a Discord bot, a scoreboard for their bar, a portfolio project — most with no caching, polling every few seconds, deployed and forgotten. That is a lot of unplanned load on systems that were sized for ESPN's own traffic, not for everyone else's hobby projects too. The likely outcomes are all bad for the people relying on it: aggressive rate limiting, auth requirements, or the endpoints simply being locked down.</p><h2>If you use it anyway</h2><p>NOTE: I do not support using endpoints that are not free use or have a contract of use. The following is general best practice when using any APIs.</p><ul><li><strong>Cache hard.</strong> Scores do not change every second. Poll on the order of minutes, not seconds, and serve cached data to your own users.</li><li><strong>Fail gracefully.</strong> Assume any field can vanish and any request can start returning a 403. Do not let ESPN going dark take your whole app with it.</li><li><strong>Do not build a business on it.</strong> It is undocumented and unsupported for a reason. If it matters, pay for a real sports data provider with a contract.</li><li><strong>Be a good guest.</strong> It is not your infrastructure. Use it the way you would want someone using yours.</li></ul><h2>Summary</h2><p>As this football season gets underway, it will be interesting to see if ESPN and many tools built using their APIs will go down due to the load. Based on the AI training data that currently exist, AI could also easily take ESPN down.</p><p>Could AI taking down ESPN and football tools be something that changes how we use it?</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>TIL</category>
            <category>ESPN</category>
            <category>API</category>
            <category>reverse engineering</category>
            <category>AI</category>
            <category>vibe coding</category>
            <category>security</category>
            <category>vulnerability</category>
            <category>football</category>
        </item>
        <item>
            <title><![CDATA[Our Country Is Divided, and Democracy Needs Action]]></title>
            <link>https://morgyn.io/post/democracy-needs-action</link>
            <guid isPermaLink="false">https://morgyn.io/post/democracy-needs-action</guid>
            <pubDate>Sun, 06 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[We are more divided than ever, and the fix is not winning an internet argument — it is civic engagement and electing people who uphold their oath. Why I built democracyneedsaction.com.]]></description>
            <content:encoded><![CDATA[<p>I try to keep this site mostly about code. This one is not about code.</p><p>We are more divided as a country than I have seen in my lifetime. It is in the way we talk about each other, the way families avoid certain topics at dinner, and the way a lot of people have quietly decided that none of it matters because nothing ever changes. I understand the exhaustion. I do not accept the conclusion.</p><h2>Division is not the same as disagreement</h2><p>A healthy democracy is supposed to contain disagreement. People want different things, weigh trade-offs differently, and come from different places. That is normal and it is fine. What is not fine is treating the other half of the country as an enemy to be defeated rather than neighbors you have to share a government with. Once that flips, every problem gets harder, because we stop even trying to solve things together.</p><p>I do not think the way out is winning an argument on the internet. I think it is slower and less satisfying than that.</p><h2>What actually helps</h2><ul><li><strong>Civic engagement.</strong> Show up. Vote in every election, not just the presidential ones. Know who represents you at the city, county, state, and federal level, and what they are actually doing.</li><li><strong>Partnerships.</strong> Change happens when groups that do not agree on everything agree on something and work on it together. Local organizations, community groups, churches, unions, libraries — the boring infrastructure of a functioning society.</li><li><strong>Communication.</strong> Talk to people who see it differently, in person, without an audience. It is harder to hate someone across a table than across a feed.</li><li><strong>Electing people who mean it.</strong> Officials take an oath to support and defend the Constitution. That oath is the job. We should elect people who treat it that way and hold the ones who do not accountable at the ballot box.</li></ul><h2>Why I built democracyneedsaction.com</h2><p>I kept telling people to "get involved" and realized I did not have a good place to point them. So I built one: <a href="https://democracyneedsaction.com" target="_blank" rel="noopener noreferrer">democracyneedsaction.com</a>.</p><p>It is nonpartisan. The line I keep coming back to is *"We don't care who you vote for, but we want you to vote."* And the design goal is *"nonpartisan simplicity"* — no outrage bait, no algorithm, just the tools.</p><p>What is on it:</p><ul><li><strong>Register to vote</strong>, check that your registration is still active, and request an absentee ballot.</li><li><strong>Election reminders and a ballot preview</strong> so you are not walking in cold.</li><li><strong>A pledge to vote</strong>, because saying it out loud makes you more likely to do it.</li><li><strong>Plain explanations</strong> of things like the makeup of the current Congress and the national debt — context without a lecture.</li><li><strong>A daily civics crossword and quizzes</strong>, because learning this stuff should not feel like homework.</li></ul><p>The <a href="https://wonkrz.store/collections/stem" target="_blank" rel="noopener noreferrer">WONKRZ store</a> is tied to it — proceeds go toward keeping people informed and engaged.</p><h2>The ask</h2><p>Go register, or go check that you are still registered. Then pick one local thing and get involved in it. That is the whole plan. It is not glamorous, but neither is democracy — it is maintenance, and it only works if enough of us keep doing it.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>blog</category>
            <category>democracy</category>
            <category>civic engagement</category>
            <category>voting</category>
            <category>Constitution</category>
            <category>elections</category>
        </item>
        <item>
            <title><![CDATA[I Built spidersinverse.com Because People Keep Searching for Spiders]]></title>
            <link>https://morgyn.io/post/spidersinverse</link>
            <guid isPermaLink="false">https://morgyn.io/post/spidersinverse</guid>
            <pubDate>Sun, 06 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Search interest in spiders spikes every autumn, so I used Claude to spin up an entire website about them in an afternoon. What the trend showed and what I learned building it.]]></description>
            <content:encoded><![CDATA[<p>I have a habit of opening <a href="https://trends.google.com/trends/" target="_blank" rel="noopener noreferrer">Google Trends</a> when I am bored and typing in whatever is on my mind. It is a nice way to find out whether a thing I care about is a thing anyone else cares about. This week the thing on my mind was spiders, mostly because I have been hanging fake webs on the porch railing and arguing with myself about whether that is too early.</p><h2>What the trend actually showed</h2><p>Turns out I am not alone. Search interest in "spiders" is not flat. It has a steady baseline all year and then a very reliable climb every autumn that peaks right around October 31. People search for what spiders look like, whether the one in their bathroom is dangerous, how to keep them out of the house, and — my favorite — "spider Halloween decorations" going nearly vertical in the second half of October.</p><p>None of that is surprising once you see it, but seeing the shape of it is different from assuming it. There is a genuine, repeating, seasonal pile of curiosity about spiders and it lines up almost perfectly with the holiday I am already decorating for.</p><h2>So I made a website</h2><p>I decided it would be fun to build a small site dedicated to spiders in time for Halloween. It is called <a href="https://spidersinverse.com" target="_blank" rel="noopener noreferrer">spidersinverse.com</a>. The name is a bit of a play on words and a bit of me not wanting to overthink domain availability.</p><p>I built it with Claude. This is becoming my normal way of starting a side project: I describe what I want, we go back and forth on structure and copy, and I end up with something real on the screen much faster than if I had opened an empty editor and stared at it. Claude handled a lot of the scaffolding and the first pass of content, and I spent my time on the parts I actually enjoy — deciding what the site should feel like, cutting the writing down, and picking which spiders were interesting enough to include.</p><h2>What is on it</h2><p>The idea is a friendly, not-too-creepy field guide. Common house spiders and how to identify them, which ones are actually worth worrying about (far fewer than people think), the myths that refuse to die, and a seasonal section on why you see more of them in the fall. And, because it is timed for Halloween, a light section on how spiders became a decoration in the first place.</p><h2>Why bother</h2><p>Partly because the trend data made it obvious that people are looking. Partly because I like having a reason to learn something in depth, and spiders turned out to be a good topic — genuinely useful, a little spooky, and seasonal without being disposable. And partly because building a whole small website in an afternoon still feels like a bit of a trick, and I am not tired of it yet.</p><p>If you are the kind of person who checks the corner of the ceiling before going to bed, go have a look. It might make you slightly less nervous. No promises.</p><p>PS: Rather than adding a Rick Roll spider while you explore, I did it upfront. 🕷️ Perhaps I may add some more in as we get closer to Halloween! 🕸️</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>blog</category>
            <category>Halloween</category>
            <category>spiders</category>
            <category>Google Trends</category>
            <category>Claude</category>
            <category>side project</category>
        </item>
        <item>
            <title><![CDATA[Tutorial: Python Dictionaries]]></title>
            <link>https://morgyn.io/post/python-dictionaries</link>
            <guid isPermaLink="false">https://morgyn.io/post/python-dictionaries</guid>
            <pubDate>Sat, 05 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Python dictionaries map unique keys to values for fast, readable lookups. A tutorial on creating them, the dict methods worth knowing, iteration, and common patterns.]]></description>
            <content:encoded><![CDATA[<p>Python dictionaries, <code>dict</code>, are one of the most powerful built-in data types. A <code>dict</code> stores data as key-value pairs, so instead of reaching for an item by its numeric position (like a <code>list</code>), you reach for it by a meaningful key. They are generally written as comma-separated <code>key: value</code> pairs inside curly braces {}.</p><h2>Key Characteristics</h2><ul><li>Key-Value Pairs: Every entry maps a unique key to a value.</li><li>Ordered: As of Python 3.7, dictionaries remember the order in which keys were inserted.</li><li>Mutable: You can add, change, or remove pairs after the dictionary is created.</li><li>Unique Keys: A key can only appear once. Assigning to an existing key overwrites its value.</li><li>Hashable Keys: Keys must be an immutable type (strings, numbers, tuples). Values can be anything.</li></ul><h2>Usage</h2><h3>Comments</h3><p>In the examples below, the usage of <code>#</code> in Python is to denote inline docstrings. They can be used on a line alone or two spaces at the end of the line.</p><pre><code># I am a single line docstring

empty_dict = {}  # I am an inline docstring
</code></pre><h3>Creating dictionaries</h3><pre><code># Empty dict, example 1
empty_dict = {}

# Empty dict, example 2
empty_dict = dict()

# Dict of string keys and string values
capitals = {"France": "Paris", "Japan": "Tokyo", "Egypt": "Cairo"}

# Mixed value types
person = {"name": "Ada", "age": 36, "is_admin": True}

# Building from a list of pairs
pairs = [("a", 1), ("b", 2)]
letters = dict(pairs)
</code></pre><p>NOTE: When making a <code>dict</code> in Python, do not name the variable <code>dict</code> as this is a built-in data type. It is common to see people use <code>d</code> or <code>*_dict</code> for variable naming conventions.</p><h3>Accessing values</h3><p>You access a value by putting its key inside square brackets.</p><p>NOTE: The <code>>>></code> is what you will see when using <code>python3</code> from the terminal. It will be used here as an example and removed in future snippets.</p><pre><code>>>> person = {"name": "Ada", "age": 36, "is_admin": True}
>>> print(person["name"])
Ada
>>> print(person["age"])
36
</code></pre><p>If you ask for a key that does not exist, you get a <code>Traceback</code> error.</p><pre><code>>>> print(person["email"])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'email'
</code></pre><p>To avoid that, use <code>get()</code>, which returns <code>None</code> (or a default you provide) instead of raising an error.</p><pre><code>person = {"name": "Ada", "age": 36}

print(person.get("email"))
None  # output

print(person.get("email", "not provided"))  # default response is "not provided"
not provided  # output
</code></pre><h3>Adding and updating</h3><p>Assigning to a key that does not exist adds it. Assigning to a key that already exists overwrites the value.</p><pre><code>person = {"name": "Ada"}

# Add a new key
person["age"] = 36
print(person)
{'name': 'Ada', 'age': 36}  # output

# Overwrite an existing key
person["age"] = 37
print(person)
{'name': 'Ada', 'age': 37}  # output

# Merge another dict in with update()
person.update({"city": "London", "age": 38})
print(person)
{'name': 'Ada', 'age': 38, 'city': 'London'}  # output
</code></pre><h3>Removing items</h3><ul><li><code>pop(key)</code>: Removes the key and returns its value (raises <code>KeyError</code> if missing, unless you pass a default).</li><li><code>popitem()</code>: Removes and returns the last inserted <code>(key, value)</code> pair.</li><li><code>del</code>: A statement that removes a key with no return value.</li><li><code>clear()</code>: Empties the dictionary.</li></ul><pre><code>person = {"name": "Ada", "age": 38, "city": "London"}

# pop a specific key and keep the value
age = person.pop("age")
print(age)
38  # output
print(person)
{'name': 'Ada', 'city': 'London'}  # output

# pop with a default so a missing key does not error
person.pop("email", None)

# remove the last inserted pair
person.popitem()
('city', 'London')  # output

# del removes a key outright
del person["name"]
print(person)
{}  # output

# attempting to pop a missing key with no default
person.pop("name")
Traceback (most recent call last):  # output
  File "<stdin>", line 1, in <module>
KeyError: 'name'
</code></pre><h3>Checking for a key</h3><p>Use <code>in</code> to test whether a key exists. This checks keys, not values.</p><pre><code>capitals = {"France": "Paris", "Japan": "Tokyo"}

print("France" in capitals)
True  # output

print("Paris" in capitals)
False  # output

print("Paris" in capitals.values())
True  # output
</code></pre><h3>Iterating through dictionaries</h3><p>#### Keys</p><p>Looping over a dictionary directly gives you its keys.</p><pre><code>capitals = {"France": "Paris", "Japan": "Tokyo", "Egypt": "Cairo"}

for country in capitals:
    print(country)

# output
France
Japan
Egypt
</code></pre><p>#### Values</p><p>Use <code>values()</code> when you only care about the values.</p><pre><code>capitals = {"France": "Paris", "Japan": "Tokyo", "Egypt": "Cairo"}

for city in capitals.values():
    print(city)

# output
Paris
Tokyo
Cairo
</code></pre><p>#### Keys and values together</p><p><code>items()</code> yields each <code>(key, value)</code> pair, which you can unpack in the loop.</p><pre><code>capitals = {"France": "Paris", "Japan": "Tokyo", "Egypt": "Cairo"}

for country, city in capitals.items():
    print(f"The capital of {country} is {city}")

# output
The capital of France is Paris
The capital of Japan is Tokyo
The capital of Egypt is Cairo
</code></pre><p>#### Comprehension</p><p>Dictionary comprehensions build a new <code>dict</code> in a single line.</p><pre><code>numbers = [1, 2, 3, 4]

# Map each number to its square
squares = {n: n**2 for n in numbers}

print(squares)
{1: 1, 2: 4, 3: 9, 4: 16}  # output

# Filter an existing dict down to a subset
prices = {"apple": 3, "banana": 1, "cherry": 5}
cheap = {name: cost for name, cost in prices.items() if cost < 4}

print(cheap)
{'apple': 3, 'banana': 1}  # output
</code></pre><h3>Common patterns</h3><p>#### Counting with get</p><p>A quick way to tally occurrences without a separate library.</p><pre><code>words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
counts = {}

for word in words:
    counts[word] = counts.get(word, 0) + 1

print(counts)
{'apple': 3, 'banana': 2, 'cherry': 1}  # output
</code></pre><p>#### setdefault</p><p><code>setdefault(key, default)</code> returns the value for a key, inserting the default first if the key is missing. It is handy for grouping.</p><pre><code>people = [("eng", "Ada"), ("art", "Bo"), ("eng", "Cy")]
teams = {}

for team, name in people:
    teams.setdefault(team, []).append(name)

print(teams)
{'eng': ['Ada', 'Cy'], 'art': ['Bo']}  # output
</code></pre><p>#### Copying</p><p>Assigning a dictionary to a new variable does not copy it, both names point at the same object. Use <code>copy()</code> for a shallow copy.</p><pre><code>original = {"a": 1}
alias = original
alias["b"] = 2
print(original)
{'a': 1, 'b': 2}  # output, the original changed too

original = {"a": 1}
duplicate = original.copy()
duplicate["b"] = 2
print(original)
{'a': 1}  # output, untouched
</code></pre><h2>Summary</h2><p>I hope you find this short write-up on Python dictionaries useful. Alongside lists, dictionaries are the data type I have reached for most in my career, usually any time I need to look something up quickly by name instead of by position. They are helpful when you have to run <code>O(1)</code> lookups on data and a great tool for normalization.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>tutorial</category>
            <category>Python</category>
            <category>dictionaries</category>
            <category>methods</category>
        </item>
        <item>
            <title><![CDATA[Did I want to continue working to make millionaires richer?]]></title>
            <link>https://morgyn.io/post/did-i-want-to-continue-working-to-make-millionaires-richer</link>
            <guid isPermaLink="false">https://morgyn.io/post/did-i-want-to-continue-working-to-make-millionaires-richer</guid>
            <pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Doing three people's jobs for a 'Meets Expectations' review was not why I left. The bigger reason: I did not want to keep working to make millionaires and billionaires richer.]]></description>
            <content:encoded><![CDATA[<p>I quit my job. The biggest reason: democracy matters.</p><p>I worked as an Engineering Manager, though in practice I was also a developer, technical product manager, project and scrum master, and whoever else the work needed. I supported at least five repositories and three teams beyond my own.</p><h2>The reasons that stacked up</h2><p>I consistently did more than others in comparable roles, and my performance review still came back as "Meets Expectations," with a note that I was "emotional." I would not call myself emotional. I am blunt and to the point, and I believe in empowerment leadership and giving feedback immediately instead of letting it sit. That review hit hard, because it is not how I operate. After a lot of self-reflection, I realized the review was a symptom, not the cause, or was it? I was not happy at the company, and everything happening in our government only deepened that.</p><p>One day the CEO told us, "You are all going to work until you are 70, and there is nothing I can do about it." That landed. We live in a country built around the needs of a small number of very wealthy people, small relative to the overall population of the United States. Some trace the shift to the Clinton years and the Democrats who crossed over to the Republican party, but what we have now has been building for decades.</p><p>I had fixed the app that kept crashing and done the performance work that let the company scale it substantially, and I saw only a small bonus in comparison for the value provided. The products were built by many people and I was not solely responsible for the revenue, but the pattern was clear: executives received equity, and the people doing the work did not.</p><p>Somewhere in there I also lost my enjoyment for the work itself. My creativity was gone and I had no motivation left.</p><h2>Why democracy was the one that mattered</h2><p>I am all for capitalism, but workers should be adequately compensated for the value they provide, and right now nothing is maintaining that balance. I would argue this is the most corrupt administration in our history, with elected officials who no longer serve the people. In school I learned that rising economic inequality correlates directly with rising crime, and we are seeing that now, whatever the government reports. We are seeing more conflicts with law enforcement, including ICE and the crimes its agents commit. And we are watching tech CEOs and oligarchs get richer than anyone in this country ever has.</p><p>Instead of helping rich people get richer, I wanted to do something with a greater purpose, something that could support our democracy by improving civic engagement and political education. When young voters cast ballots on "vibes," as many did in the last presidential election, the country is in trouble. I wanted to be another voice in the growing civic discourse rather than another employee making the wealthy wealthier.</p><p>The rise of AI changes the math. It is a climate disaster unfolding in real time through data center growth, but it also gives people like you and me a chance to take some power back from the large tech companies. Small teams can build and ship quickly now. We do not have to work for companies that treat us as numbers, or as tools to be discarded. So, I decided to quit once I had at least a year of expenses saved, the F-you money we should all have, and find out whether I could earn enough to keep working for myself.</p><p>I also decided I would rather work as a barista at a coffee shop than stay in that job. Before I finished school I worked plenty of customer service roles, and I liked being around people and helping them more than I liked what I was doing now. Working for myself, or starting a business, was the natural next step.</p><h2>What "something new" looks like</h2><p>My creativity has come back, and I am more motivated than I have been in a long time.</p><p>I set up a few sites to build out my portfolio as a backup, in case I need to look for a job next year or the year after. The advantage of being a developer is that you can build things faster and more cheaply than someone who has to pay for every service. Over the last few weeks I have launched the following, using either React apps deployed through GitHub Actions or Shopify:</p><ul><li><a href="https://morgyn.io/" target="_blank" rel="noopener noreferrer">morgyn.io</a> - My fun tech site, with utilities I commonly find co-workers using, games, and a few other things.</li><li><a href="https://wonkrz.store/" target="_blank" rel="noopener noreferrer">wonkrz.store</a> - Pro-democracy apparel with no political party affiliation. A share of the proceeds goes to political activism and civic engagement. More to come on this.</li><li><a href="https://wonkrz.com/" target="_blank" rel="noopener noreferrer">wonkrz.com</a> - A simple site that provides voting and government information to help raise civic knowledge online.</li></ul><p>The t-shirt store is the one I keep coming back to. I have wanted to do one for a long time, and I find myself making designs more often than I write blog posts for the tech site. I have many designs sitting on my computer still not yet added to the site. I have run e-commerce before and learned that an online store generates more revenue than selling in person and it is easier to start down the path of least resistance initially. There is a lot of competition now, plenty of people and shops printing shirts, so we will see how it goes. Either way, the outcome is in my hands. What I earn reflects the effort I put in, and no one else profits from my work. If it goes well, I can send some of the proceeds to charities and causes that strengthen our democracy.</p><h2>Summary</h2><p>I plan to keep making and building things. When something does well, I will put more time into it and see whether I can use it to empower the people around me, or people in less fortunate situations than mine. That is probably where I sound more like a socialist. If I earn more than I need to survive, I will hire people to help and split the revenue evenly. I refuse to enrich myself on the back of someone else's work and I don't want to enrich others off of my work.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>blog</category>
            <category>democracy</category>
            <category>tech</category>
            <category>quit</category>
            <category>Shopify</category>
            <category>React</category>
            <category>millionaires</category>
            <category>billionaires</category>
        </item>
        <item>
            <title><![CDATA[TIL: Halloween Origins]]></title>
            <link>https://morgyn.io/post/til-halloween</link>
            <guid isPermaLink="false">https://morgyn.io/post/til-halloween</guid>
            <pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Halloween traces back to Samhain, the ancient Celtic new year when the boundary between the living and the dead was believed to thin. A quick history.]]></description>
            <content:encoded><![CDATA[<p>Today I did not want to write about coding. I have been doing some Halloween t-shirt designs today in preparation for the coming holiday. Surprisingly, I have never actually looked up the origins of Halloween.</p><p>TIL: It has Pagan origins, like all the best holidays 😉 and is believed to have connections to the festival of Samhain among the Celts of ancient Ireland.</p><p>On the day roughly corresponding to October 31/November 1, the new year was believed to begin. It was considered the beginning of the winter period, when livestock were brought in from pasture and land tenures were renewed. This makes sense as one year I was trick or treating as a child in the middle of a snow storm.</p><p>It was a common belief that the boundary between the worlds of the living and dead blurred, allowing spirits to roam on earth. It was held that the souls of those who had died returned to visit their homes and those who had died during the year journeyed to the otherworld. Bonfires were set and people would sometimes wear masks and other disguises to avoid being recognized by the ghosts.</p><p>Yes, there are some Christian origins, but there is some considerations that they were set to replace the Pagan holidays. As I have gotten older, I do sometimes feel like the Pagans knew how to have the best time.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>TIL</category>
            <category>Halloween</category>
            <category>Samhain</category>
        </item>
        <item>
            <title><![CDATA[Tutorial: Convert Image Files to WebP]]></title>
            <link>https://morgyn.io/post/png-to-webp</link>
            <guid isPermaLink="false">https://morgyn.io/post/png-to-webp</guid>
            <pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[WebP images run 25-34% smaller than JPEG and PNG. A short tutorial on batch-converting your images from the command line with cwebp to speed up your site.]]></description>
            <content:encoded><![CDATA[<p>You can easily convert <code>png</code> files to <code>webp</code> using the terminal for free!</p><p><a href="https://developers.google.com/speed/webp/" target="_blank" rel="noopener noreferrer">WebP</a> was developed by Google, which announced the open-source image format in September 2010. WebP is a modern image format that provides superior lossless and lossy compression for images on the web. Using WebP, users can create smaller, richer images that make the web faster. The images are 26% smaller in size compared to PNGs and 25-34% smaller than comparable JPEG images.</p><p>First, you must have <a href="https://brew.sh/" target="_blank" rel="noopener noreferrer">brew</a> installed. Once <code>brew</code> is installed, you will need to run the following command in your terminal:</p><pre><code>brew install webp
</code></pre><p>Once installation is complete, you can go to the directory containing the image and run the conversion command in the terminal:</p><pre><code>cwebp input.png -o output.webp
</code></pre><p>And, Bob's Your Uncle! Have fun making your site faster!</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>tutorial</category>
            <category>png</category>
            <category>jpeg</category>
            <category>image compression</category>
            <category>webp</category>
            <category>cli</category>
            <category>brew</category>
        </item>
        <item>
            <title><![CDATA[How to spot AI videos as they grow increasingly better]]></title>
            <link>https://morgyn.io/post/how-to-spot-ai-videos-part-1</link>
            <guid isPermaLink="false">https://morgyn.io/post/how-to-spot-ai-videos-part-1</guid>
            <pubDate>Mon, 31 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[An AI attack ad helped end Thomas Massie's primary. The tells — hands, physics, lighting, audio sync — that still give AI-generated video away, for now.]]></description>
            <content:encoded><![CDATA[<p>AI videos are becoming increasingly sophisticated and fooling more and more people online. Thomas Massie, in large part, lost his primaries due to an AI video that was generated by PAC advertising. This video showed Massie, AOC, and Ilhan Omar and checking into a hotel together, which fooled many older voters into voting for others resulting in his loss. Polling performed after the primary indicated this as people had thought the video was real. With the president increasingly using AI videos, this election in November may play into the gullibility of many more Americans.</p><p>Today, on Bluesky, I saw Mark Hamill post an <a href="https://www.instagram.com/reel/DcnaK2GTG2W/" target="_blank" rel="noopener noreferrer">AI video of a child getting up on a park bench and kissing a woman painted as a golden statue and they both laughed at each other</a>. While the concept is cute, this is clearly an AI video.</p><p>What are the key signs?</p><ul><li>The child someone gets up onto a wooden park bench and holds onto the woman or bench with their hand that would not be touching anything if you were to follow the natural length of the child’s arm.</li><li>The child magically stands in air with their left foot as it does not align with the park bench.</li><li>When the infant places their right arm around the statue, you can see the clipped images overlapping on each other without the natural blend that is observed with shadows.</li><li>Another person randomly pops up in the background after the child kisses the statue.</li><li>The leaves on the trees don’t move! It is uncommon for the leaves on trees to be completely stationary. In this video, there is no subtle movement that we would expect. This is a tell-tale sign of AI.</li><li>The shadows on the woman do not align with the shadows on the child. Also, the woman somehow has light shining on her, when everyone else has shadows on their face.</li></ul><p>The AI videos are getting increasingly better, but one of the key indicators still is the pixelation and shadowing does not match. In the Massie video, a security camera somehow had enough detail to show who the people are, where it should have shown a lot more grain and pixelation. If you look closely enough, it does appear that they rendered the video from people who looked similar and they deepfaked the faces. When AI fixes the shadows, pixelation, and blurring on videos, we are going to see more and more people able to fake alibis in court and an increase in crime.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>AI</category>
            <category>risks</category>
            <category>deep fake</category>
            <category>AI videos</category>
        </item>
        <item>
            <title><![CDATA[AI and the risks are more than reported]]></title>
            <link>https://morgyn.io/post/ai-risks</link>
            <guid isPermaLink="false">https://morgyn.io/post/ai-risks</guid>
            <pubDate>Mon, 31 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Bill Gates named three AI risks and left out the data-center water and electricity costs Erin Brockovich is documenting — and the question of who captures the wealth.]]></description>
            <content:encoded><![CDATA[<p>Bill Gates recently wrote a post about the <a href="https://www.gatesnotes.com/a-turbulent-ai-era-and-critical-choices-to-make" target="_blank" rel="noopener noreferrer">critical choices of AI</a>, however, he is missing many key critical issues with AI that the talented <a href="https://www.brockovichdatacenter.com/" target="_blank" rel="noopener noreferrer">Erin Brockovich has been compiling</a>.</p><p>When he highlights that the three big risks: jobs disappearing, AI empowering people, and stunting childhood development and human relationships, he is missing some of the main issues affecting the everyday Americans. When you become substantially wealthy, then your perspective on an issue is not what most people see.</p><p>What I see, CEOs and executives pushing for AI usage for cost cutting and getting investor money. Investors, for a while now, have only been investing in AI and thus many companies pivoted to put AI in everything to capture that investor money. I also see everyday Americans struggling with energy costs due to AI data center usage on the energy grid that is not built to handle the influx of usage. I see violations of the <a href="https://www.epa.gov/laws-regulations/summary-clean-air-act" target="_blank" rel="noopener noreferrer">Clean Air Act</a> as data centers rush to power AI. I see executives who are building data centers require elected officials to sign NDAs and push through construction against the wishes of the communities they represent. I see people's water wells run dry as data centers pull from those wells.</p><p>The boots on the ground tell a different story than those at the top. While I am fully behind us building AI and leveraging it, I am also for the everyday American!</p><p>We are at a critical time in our history where it will now become easier for people to compete against these giant tech oligarchs. We can use the tools they created to shift the balance towards the people. We no longer need to pay the costs for their services since we now have the tools to quickly build the services ourselves. Time will tell what the future looks like, but we have to be engaged to tackle these issues. We cannot be complacent and must take action at the ballot boxes in each and every election.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>AI</category>
            <category>risks</category>
            <category>data centers</category>
            <category>technological evolution</category>
        </item>
        <item>
            <title><![CDATA[Tutorial: Python Lists]]></title>
            <link>https://morgyn.io/post/python-lists</link>
            <guid isPermaLink="false">https://morgyn.io/post/python-lists</guid>
            <pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Python lists hold ordered, mutable, mixed-type collections. A tutorial covering list methods, indexing and slicing, iteration, and list comprehensions with examples.]]></description>
            <content:encoded><![CDATA[<p>Python <code>lists</code> are one of the most versatile and frequently used built-in data types. Lists are used to store ordered collections of items in a single variable, and generally written as comma-separated values inside square brackets [].</p><h2>Key Characteristics</h2><ul><li>Ordered: Elements maintain their exact insertion order. The do not re-order like <code>sets</code>.</li><li>Mutable: You can modify, add, or remove items after the list is created.</li><li>Heterogeneous: A single list can contain multiple different data types (strings, integers, booleans, or even other lists) at the same time.</li><li>Allow Duplicates: Because lists use index numbers, elements with identical values can exist peacefully side-by-side.</li></ul><h2>Usage</h2><h3>Comments</h3><p>In the examples below, the usage of <code>#</code> in Python is to denote inline docstrings. They can be used on a line alone or two spaces at the end of the line.</p><pre><code># I am a single line docstring

empty_list = []  # I am an inline docstring
</code></pre><h3>Creating lists</h3><pre><code># Empty list, example 1
empty_list = []

# Empty list, example 2
empty_list = list()

# List of strings
fruits = ["apple", "banana", "cherry"]

# Mixed data types
mixed_list = [42, "hello", True, 3.14]
</code></pre><p>NOTE: When making a <code>list</code> in Python, do not call it a <code>list</code> as this is a built-in data type. It is common to see people use <code>lst</code> or <code>*_list</code> for variable naming conventions.</p><h3>Accessing elements of a list</h3><p>Since the order of the elements within a list are maintained on how they are added, you can access the elements using the index. The first item in a <code>list</code> will start at index <code>0</code>.</p><p>NOTE: The <code>>>></code> is what you will see when using the <code>python3</code> from the terminal. It will be used here as an example and removed in future snippets.</p><pre><code>>>> fruits = ["apple", "banana", "cherry"]
>>> print(fruits[0])
apple
>>> print(fruits[1])
banana
>>> print(fruits[2])
cherry
</code></pre><p>If you try to access a list element outside the specified range, then you will encounter a <code>Traceback</code> error.</p><pre><code>>>> print(fruits[3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
</code></pre><h3>Slicing</h3><p>Slicing in Python is a powerful feature that allows you to extract specific portions (or subsets) of sequences like strings, lists, tuples, and ranges</p><p>You can extract a sublist by defining a range [start:end]. The end index is exclusive.</p><pre><code>numbers = [0, 1, 2, 3, 4, 5, 6]
# get item at index 1 through 4
print(numbers[1:4])
[1, 2, 3]

# Exclude the first two objects in a list
print(numbers[2:])
[2, 3, 4, 5, 6]

# Exclude the last two objects in a list
print(numbers[:-2])
[0, 1, 2, 3, 4]

# Only return the first two objects in a list
print(numbers[:2])
[0, 1]

# Only return the last two objects in a list
print(numbers[-2:])
[5, 6]
</code></pre><h3>Common list methods and function</h3><p>There are several list methods that you may leverage depending on your need.</p><ul><li><code>append(obj)</code>: Adds an object to the very end of the list.</li><li><code>insert(index, obj)</code>: Inserts an object at a specific position.</li><li><code>extend(iterable)</code>: Appends objects from another list or iterable to the end.</li><li><code>pop(index)</code>: Removes and returns the item at the given index. If no index is provided, it removes the last item.</li><li><code>remove(obj)</code>: Removes the first occurrence of a specific value (raises a <code>Traceback</code> error if not found).</li><li><code>len(list)</code>: A built-in function (not a method) that returns the total count of elements.</li></ul><pre><code># Add an item to the end of the list
numbers.append(99)
print(numbers)
[0, 1, 2, 3, 4, 5, 6, 99]  # output

# Insert an object as a specific position
numbers.insert(1, 86)
print(numbers)
[0, 86, 1, 2, 3, 4, 5, 6, 99]  # output

# Extend a list with another list
numbers2 = [50, 51, 55]
numbers.extend(numbers2)
print(numbers)
[0, 86, 1, 2, 3, 4, 5, 6, 99, 50, 51, 55]  # output

# You may commonly make the mistake between append and extend in your code
numbers.append(numbers2)
print(numbers)
[0, 86, 1, 2, 3, 4, 5, 6, 99, [50, 51, 55]]  # output

# If this happens, you can use pop, which defaults to the last element
numbers.pop()
[50, 51, 55]  # output
print(numbers)
[0, 86, 1, 2, 3, 4, 5, 6, 99]  # output

# pop a specific index
numbers.pop(1)
86  # output
print(numbers)
[0, 1, 2, 3, 4, 5, 6, 99]  # output

# remove a specific occurance of a object
numbers.remove(99)
>>> print(numbers)
[0, 1, 2, 3, 4, 5, 6, 50, 51, 55]  # output

# let's reset and show how it works when you have two of the same object
numbers.append(99)
numbers.append(99)
print(numbers)
[0, 1, 2, 3, 4, 5, 6, 50, 51, 55, 99, 99]  # output
numbers.remove(99)
print(numbers)
[0, 1, 2, 3, 4, 5, 6, 50, 51, 55, 99]  # output: only first occurance removed

# attempting to remove an object that is not in the list
numbers.remove(100)
Traceback (most recent call last):  # output
  File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list

# get the length of the list
len(numbers)
11   # output
</code></pre><h3>Iterating through lists</h3><p>You will commonly have to iterate through a list and there are a few approaches:</p><p>#### Using for</p><p>The <code>for</code> loop is the most common method to iterate and read a list.</p><pre><code>fruits = ["apple", "banana", "cherry"]

for fruit in fruits:
    print(fruit)

# output
apple
banana
cherry
</code></pre><p>#### Using enumerate</p><p>If you need to know both the item and its position (index) in the list, wrap the list in <code>enumerate()</code>.</p><pre><code>fruits = ["apple", "banana", "cherry"]

for index, fruit in enumerate(fruits):
    print(f"Index {index}: {fruit}")

# output
Index 0: apple
Index 1: banana
Index 2: cherry
</code></pre><p>#### Using range</p><p>If you need to overwrite or change the items inside the original list, you must iterate using their index numbers. Depending on the action, I will sometimes prefer to create a new list, but this isn't always practical depending on the size of the list.</p><pre><code>numbers = [1, 2, 3, 4]

for i in range(len(numbers)):
    numbers[i] *= 2  # Multiplies every number by 2

print(numbers)
[2, 4, 6, 8]  # output
</code></pre><p>#### Comprehension</p><p>If you want to loop through a list, modify the values, and save them into a new list, list comprehensions offer a clean, single-line shortcut.</p><pre><code>numbers = [1, 2, 3, 4]

# Creates a new list with squared values
squares = [x**2 for x in numbers]

print(squares)
[1, 4, 9, 16]  # output
print(numbers)
[1, 2, 3, 4]  # output, orginal list
</code></pre><h2>Summary</h2><p>I hope you find this short write-up on Python lists useful. Lists are one of the most commonly used data types aside from dictionaries that I have used in my career.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>tutorial</category>
            <category>Python</category>
            <category>lists</category>
            <category>methods</category>
        </item>
        <item>
            <title><![CDATA[Tutorial: Typescript Data Types]]></title>
            <link>https://morgyn.io/post/typescript-data-types</link>
            <guid isPermaLink="false">https://morgyn.io/post/typescript-data-types</guid>
            <pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[How TypeScript adds compile-time safety to JavaScript: the primitive types, structural object types, and the advanced utility types you will reach for most.]]></description>
            <content:encoded><![CDATA[<p>TypeScript data types extend JavaScript's dynamic primitives to provide strong static compile-time type-safety. They are split primarily into primitive types, structural object types, and advanced utility types.</p><p>Here is a breakdown of the core types you will use in the <a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank" rel="noopener noreferrer">TypeScript Handbook</a>:</p><h2>Primitive Types</h2><p>Primitive types represent single, simple, and immutable values. Always use lowercase keywords for these types.</p><ul><li><code>string</code>: Text data enclosed in quotes or backticks.</li><li><code>number</code>: All numeric values, including integers and floating-point values.</li><li><code>boolean</code>: Flag values containing either true or false.</li><li><code>bigint</code>: Whole numbers that are larger than 2⁵³ - 1.</li><li><code>symbol</code>: Unique identifiers commonly used for creating object keys.</li><li><code>null</code>: The intentional absence of any value.</li><li><code>undefined</code>: Uninitialized variables that have not been assigned any value.</li></ul><h2>Object & Structural Types</h2><p>These represent more complex collections of information and structures.</p><ul><li><code>object</code>: Any value that is not a primitive type.</li><li><code>Array</code>: A collection of elements that share the exact same type (written as <code>type[]</code> or <code>Array<type></code>).</li><li><code>Tuple</code>: A fixed-length array where every sequential index has a predefined type.</li><li><code>Enum</code>: A set of named constants that help you group related numeric or string values.</li></ul><h2>Special Type-System Keywords</h2><p>TypeScript includes unique placeholders to manage dynamic or uncertain data types during compilation.</p><ul><li><code>any</code>: Disables type-checking entirely for that variable (avoid using this wherever possible).</li><li><code>unknown</code>: A type-safe alternative to <code>any</code>. You must perform a runtime check before assigning it elsewhere. TypeScript 3.0 introduced this type. Anything is assignable to <code>unknown</code>, but <code>unknown</code> isn’t assignable to anything but itself and <code>any</code> without a type assertion or a control flow based narrowing. Likewise, no operations are permitted on an <code>unknown</code> without first asserting or narrowing to a more specific type.</li><li><code>void</code>: Commonly used as the return type for functions that don't return anything.</li><li><code>never</code>: Represents values that will never occur (e.g., a function that always throws an error).</li></ul><h2>Advanced Types</h2><p>You can compose multiple types to create highly specific code requirements.</p><ul><li><code>Union Types</code>: Allows a variable to hold one of several distinct types using the pipe (|) operator.</li><li><code>Intersection Types</code>: Combines multiple object structures together into one using the ampersand (&) operator.</li><li><code>Literal Types</code>: Restricts a variable's value to a very specific set of exact strings, numbers, or booleans.</li></ul><h2>Type Syntax Summary Table</h2><table><thead><tr><th style="text-align: left">Data Type Category</th><th style="text-align: left">Common Example Syntax</th></tr></thead><tbody><tr><td style="text-align: left">String Primitive</td><td style="text-align: left"><code>let name: string = "Alice";</code></td></tr><tr><td style="text-align: left">Number Primitive</td><td style="text-align: left"><code>let age: number = 30;</code></td></tr><tr><td style="text-align: left">Array</td><td style="text-align: left"><code>let scores: number[] = [90, 80, 95];</code></td></tr><tr><td style="text-align: left">Tuple</td><td style="text-align: left"><code>let coordinates: [number, number] = [45.1, -12.3];</code></td></tr><tr><td style="text-align: left">Union</td><td style="text-align: left"><code>let id: string | number = 101;</code></td></tr><tr><td style="text-align: left">Object Shape</td><td style="text-align: left"><code>let user: { name: string; id: number };</code></td></tr></tbody></table>]]></content:encoded>
            <author>MsStryker</author>
            <category>typescript</category>
            <category>tutorial</category>
            <category>data types</category>
        </item>
        <item>
            <title><![CDATA[Tutorial: Python Data Types]]></title>
            <link>https://morgyn.io/post/python-data-types</link>
            <guid isPermaLink="false">https://morgyn.io/post/python-data-types</guid>
            <pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A tutorial on every built-in Python data type — numbers, strings, lists, tuples, sets, dicts — which are mutable, which are not, and the interview answers to know.]]></description>
            <content:encoded><![CDATA[<p><a href="https://www.python.org/" target="_blank" rel="noopener noreferrer">Python</a> is a dynamically typed language, where you do not need to explicitly declare a variable's type; the interpreter infers it at runtime. You can check any value's type using the built-in <code>type()</code> function, thus you should never define a variable as <code>type</code> in Python otherwise you will have unintended side-effects.</p><p>NOTE: Everything is an object in Python.</p><p>In many of my phone screening interviews for Python, I was asked about the various data types in Python and to explain them. Understanding these are</p><h2>Numeric Types</h2><p>Used to represent and store numbers.</p><ul><li><code>int</code>: Whole numbers of unlimited length, positive or negative (e.g., <code>42</code>, <code>-7</code>).</li><li><code>float</code>: Numbers containing a decimal point or written in scientific notation (e.g., <code>3.14</code>, <code>-0.001</code>, <code>2.5e2</code>).</li><li><code>complex</code>: Numbers containing a real and an imaginary part, written with a j (e.g., <code>3 + 5j</code>).</li></ul><h2>Text Type</h2><p>Used to store textual data.</p><ul><li><code>str</code>: A sequence of characters enclosed in single, double, or triple quotes (e.g., <code>"hello"</code>, <code>'world'</code>, <code>"""multiline"""</code>).</li></ul><h2>Sequence Types</h2><p>Used to store collections of data in an ordered format.</p><ul><li><code>list</code>: Ordered, based on how items are added to the list, mutable (changeable) collections that allow duplicate elements. Defined using square brackets (e.g., <code>[1, "apple", 3.4]</code>). If you defined a list as <code>[1, 3, 2, 9, 2, 4]</code>, that is how the order will remain.</li><li><code>tuple</code>: Ordered, immutable (unchangeable) collections that allow duplicates. Defined using parentheses (e.g., <code>(10, 20, 30)</code>).</li><li><code>range</code>: Generates a sequence of numbers, commonly used for looping (e.g., <code>range(0, 5)</code>).</li></ul><h2>Mapping Type</h2><p>Used to store data collections in an associative format.</p><ul><li><code>dict</code>: Unordered (but preserves insertion order since Python 3.7), mutable collections of key-value pairs. Keys must be unique (e.g., <code>{"name": "Alice", "age": 25}</code>).</li></ul><h2>Set Types</h2><p>Used to store unordered collections of unique elements.</p><ul><li><code>set</code>: Ordered, mutable collections with no duplicate items. Defined using curly braces (e.g., <code>{1, 2, 3}</code>). If you defined a set as <code>{2,1,3}</code> it will return as <code>{1,2,3}</code>.</li><li><code>frozenset</code>: The immutable version of a standard set.</li></ul><h2>Boolean Type</h2><p>Used for conditional operations.</p><ul><li><code>bool</code>: Represents only two values: True or False (always capitalized).</li></ul><h2>None Type</h2><ul><li>NoneType: A special type representing the absence of a value, represented by the keyword <code>None</code>.</li></ul><h2>Mutable vs Immutable</h2><p>Mutable objects can be updated in place without changing memory addresses.</p><p>Immutable objects cannot be altered once created. Any modification forces the program to create a brand-new object in memory.</p><table><thead><tr><th style="text-align: left">Data Type</th><th style="text-align: left">Type Category</th><th style="text-align: left">Mutable?</th><th style="text-align: left">Example Syntax</th></tr></thead><tbody><tr><td style="text-align: left"><code>int</code> / <code>float</code></td><td style="text-align: left">Numeric</td><td style="text-align: left">❌ No</td><td style="text-align: left"><code>x = 5</code></td></tr><tr><td style="text-align: left"><code>str</code></td><td style="text-align: left">Text</td><td style="text-align: left">❌ No</td><td style="text-align: left"><code>x = "hello"</code></td></tr><tr><td style="text-align: left"><code>list</code></td><td style="text-align: left">Sequence</td><td style="text-align: left">Yes</td><td style="text-align: left"><code>x = [1, 2]</code></td></tr><tr><td style="text-align: left"><code>tuple</code></td><td style="text-align: left">Sequence</td><td style="text-align: left">❌ No</td><td style="text-align: left"><code>x = (1, 2)</code></td></tr><tr><td style="text-align: left"><code>dict</code></td><td style="text-align: left">Mapping</td><td style="text-align: left">Yes</td><td style="text-align: left"><code>x = {"a": 1}</code></td></tr><tr><td style="text-align: left"><code>set</code></td><td style="text-align: left">Set</td><td style="text-align: left">Yes</td><td style="text-align: left"><code>x = {1, 2}</code></td></tr></tbody></table>]]></content:encoded>
            <author>MsStryker</author>
            <category>python</category>
            <category>tutorial</category>
            <category>data types</category>
        </item>
        <item>
            <title><![CDATA[Stop Using BLACK_LIST and WHITE_LIST]]></title>
            <link>https://morgyn.io/post/blacklist</link>
            <guid isPermaLink="false">https://morgyn.io/post/blacklist</guid>
            <pubDate>Sun, 23 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The terms carry a history that predates computing. Clearer, more inclusive alternatives like allowlist and blocklist that also read better in a codebase.]]></description>
            <content:encoded><![CDATA[<p>Black Like Me, first published in 1961, is a nonfiction book by journalist John Howard Griffin, who had his skin color medically altered to pass as a black man. He recounting his journey in the Deep South of the United States, at a time when African Americans lived under the Jim Crow laws. It was one of my favorite books I read for my own enjoyment in high school. It was never on our reading list, and I wish it was. There was not enough black history taught in my all white school.</p><p>The statement "Racism Is So American That When You Protest It, People Think You Are Protesting America" or "racism is as American as apple pie" is used to show how racial inequality is engrained in American life.</p><p>Some of the terms we hear all the time on news and within many codebases still is <code>WHITE_LIST</code> and <code>BLACK_LIST</code>. Without going further, can you understand what these terms represent at the outset?</p><p>These terms are deeply entrenched in segregation, where white are the allowed class of citizens and black are the others (less than) or deny class of citizens. In my previous job, I had to explain why this terminology is problematic and people still didn't care or go about changing. Thus, I personally changed any code I worked in to using <code>ALLOW_LIST</code> and <code>DENY_LIST</code> as this is more inclusive and makes the environment more welcoming to black developers. Many vendors or agencies we would work with would also use this terminology and I would constantly 🤦.</p><p>Now, with the ever entrenching of AI, racism is becoming more entrenched in our daily lives as AI is trained on deeply rooted racist data.</p><p>Some people don't understand why this is problematic as they have never experienced being looked at differently because of their skin color. They have never experienced being denied a job because of their skin color. They have never been pulled over for "driving while black". They have never had to not wear a hoodie (most common developer attire) when going out for fear of a police officer harassing them or worse.</p><p>I have not experienced what it is like for a black person, but I lived in Hilo, HI and I did experience being denied jobs for being a white person and not Hawaiian or Pacific Islander. I had coworkers treat me as less than and who didn't speak to me for months until I had proven myself. I am grateful for this experience because it gives me more empathy for those who have different skin than my own.</p><p>We should all strive to create inclusivity for all and learn that what we were taught isn't necessarily what we should propagate.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>#BLM</category>
            <category>inclusivity</category>
            <category>Jim Crow</category>
        </item>
        <item>
            <title><![CDATA[My First HTML Resource]]></title>
            <link>https://morgyn.io/post/w3</link>
            <guid isPermaLink="false">https://morgyn.io/post/w3</guid>
            <pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Before frameworks and component libraries, learning HTML and CSS by hand made the web feel creative. Why the fundamentals still matter and where to learn them.]]></description>
            <content:encoded><![CDATA[<p>Depending on your age, you may not remember when you could style you myspace or facebook page. I would commonly stay up late at night styling pages and teaching myself html and CSS. Being able to visualize your creativity was a fun experience. Now, most developers use frameworks with built in components to help you render common components quickly. There are days that I sometimes find myself going back to the basics.</p><h2>Why should you learn basic HTML and CSS?</h2><p>Not everyone accesses the internet on the latest computers, tablets, or phones. Some people will access websites using older devices that do not support the latest React components. When doing web development, you must first recognize who your audience is. If for instance, you are building a government website for disadvantaged people, you will most likely want a basic site with the foundational HTML and CSS to allow it to be accessible by their older devices.</p><p>If you find yourself in this position, going back to basic resources will most likely be necessary.</p><h2>The Resource</h2><p>If you are interested in learning the basics and several different languages, I highly recommend <a href="https://www.w3schools.com/" target="_blank" rel="noopener noreferrer">W3Schools</a> as it is a widely used, free educational website founded in 1998 that specializes in teaching web development through text-based tutorials and interactive, in-browser "Try It Yourself" code editors. Covering languages from HTML to Python, the platform also offers website hosting through W3Schools Spaces and optional paid certifications to validate learning.</p><p>For more details, visit <a href="https://www.w3schools.com/" target="_blank" rel="noopener noreferrer">W3Schools</a>.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>HTML</category>
            <category>CSS</category>
            <category>Web Development</category>
        </item>
        <item>
            <title><![CDATA[AI Is Full of It!]]></title>
            <link>https://morgyn.io/post/ai-is-full-of-it</link>
            <guid isPermaLink="false">https://morgyn.io/post/ai-is-full-of-it</guid>
            <pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Why we should call AI hallucinations what they are — bugs — and how large language models repeat their training data and its embedded bias with total confidence.]]></description>
            <content:encoded><![CDATA[<p>AI is full of 💩 sometimes!</p><p>We like to call it "hallucinations", but why do we use that term? When software doesn't perform as expected, we typically say it has a "bug" 🐛. So, why do we not say that AI has a bug if it is not performing as expected? Why has Microsoft recently said the usage of Copilot was for entertainment purposes?</p><h2>AI: Artificial Intelligence</h2><p>Many people think that AI is actually intelligent. However, it is not!</p><p>It is, Stochastic Parrots, as authored by Timnit Gebru, Emily M. Bender, Angelina McMillan-Major, and Margaret Mitchell in "On the Dangers of Stochastic Parrots: Can Language Models Be Too Big? 🦜". When I first watched an online talk by Timnit, I didn't fully grasp the gravity of what was coming, but I think we all do now. Google pushed Timnit out of the company over her work.</p><h3>Example</h3><p>A <code>sitemap.xml</code> is a file that Google and other search engines use to index your site and is used for Search Engine Optimization (SEO). In this example, the AI service named Claude (by Anthropic) was used. It is the AI tool that I have found to work best for software development.</p><p>Last night I tried to get Claude to generate a dynamic sitemap for me in React. Rather than saying it could not perform the action based on the libraries it itself installed, it kept trying to create one. When I tried to clarify the expected output, it would delete and try again. It first created a sitemap.xml output within the styled page. Then it created the sitemap.xml within the raw HTML <code>body</code> element 🤦. Rather than continuing in this endeavor, I stopped the hemorrhage or tokens and resorted to my old setup. This is one of the cases, where I like frameworks like Django as this is an easy setup.</p><p>AI was not intelligent enough to realize the output was incorrect in all scenarios. It, like a parrot 🦜 does, repeated what a sitemap looks like in all the wrong ways. If AI was intelligent, it would have been able to generate the expected result on the first iteration or say that it could not complete the task. Instead, it gladly wasted resources and my money.</p><h3>Racial Bias</h3><p>A <a href="https://news.stanford.edu/stories/2026/06/ai-hiring-tools-racial-bias-research" target="_blank" rel="noopener noreferrer">recent study out of Stanford</a> discusses the racial bias in AI screening tools. This is present because the data it is trained on is racist. We saw this when <a href="https://www.theguardian.com/technology/2016/mar/26/microsoft-deeply-sorry-for-offensive-tweets-by-ai-chatbot" target="_blank" rel="noopener noreferrer">Microsoft first launched an AI chat bot in 2016</a> that had to quickly be shut down. We see it now with Grok, the AI chatbot developed by xAI and integrated into X (twitter), which has repeatedly generating racist, antisemitic, and offensive content.</p><p>AI, like a parrot 🦜 does, repeats the racism that is deeply embedded in the internet and all of the training data being used.</p><p>We NEED government reform and safeguards against bias and discriminating material used to train these models and hold the companies accountable for the discrimination when using these AI tools.</p><h3>Age Bias</h3><p>Along with racial bias, there have been many reports on social media of workers over 50 not making it to the interview stage. They have had to remove all but the last 10 years of experience to get past the HR AI software. This would indicate that AI may not be trained adequately where the dataset only leverages younger worker data.</p><p>AI, like a parrot 🦜 does, repeats the age bias that exists in technology software.</p><p>We NEED government reform and safeguards to protect against age discrimination when using AI tools.</p><h3>Mental Health</h3><p>NOTE: If you or someone you know are considering hurting themselves, please visit <a href="https://988lifeline.org/" target="_blank" rel="noopener noreferrer">988 Lifeline</a>.</p><p>There are several lawsuits that families have filed against AI, a notable one was due to a family who lost their son because ChatGPT, created by OpenAI, helped show the teenager how to commit suicide. Please see the <a href="https://www.youtube.com/watch?v=WZlB0KyWBMc" target="_blank" rel="noopener noreferrer">interview Kara Swisher</a> did with the family.</p><p>AI, like a parrot 🦜 does, repeats the online troll behavior, where online trolls are people who post mean, fake, or upsetting things on the internet just to get a reaction. They use social media, chat rooms, and game lobbies to trigger reactions in others for their own amusement.</p><p>We NEED government reform on social media in general and the AI tools that perpetuate the trolling behavior.</p><h2>Summary</h2><p>I do use AI, but I try to use it sparingly because I can do many things on my own just as fast as AI, if not better, and for cheaper. There are some things that AI will do better than I can, but for now, it cannot replace what I do completely. When AI is as it says, actually intelligent, then my views will change, but for now, I stand by Timnet et al.</p><p>AI is Stochastic Parrots 🦜 and the CEOs at these companies are playing many people for fools.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>AI</category>
            <category>hallucinations</category>
            <category>BS</category>
            <category>opinion</category>
            <category>sitemap.xml</category>
            <category>claude</category>
            <category>Artificial Intelligence</category>
            <category>OpenAI</category>
            <category>Copilot</category>
            <category>Microsoft</category>
            <category>SEO</category>
        </item>
        <item>
            <title><![CDATA[Spacing For Each Language]]></title>
            <link>https://morgyn.io/post/spacing-in-code</link>
            <guid isPermaLink="false">https://morgyn.io/post/spacing-in-code</guid>
            <pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Indentation arguments end when a formatter and a pre-commit hook decide for you. The common spacing conventions per language and the tooling that enforces them.]]></description>
            <content:encoded><![CDATA[<p>Several years ago when I was developing in Python, a codebase I was working in had a combination of tabs and spaces and resulted in some hard to debug issues. I have also worked several jobs where there were many heated disagreements on formatting in the code. This is almost always solved by having a CI/CD process that checks formatting and a precommit hook that checks formatting rules before a developer can commit to the codebase.</p><p>One of the most commonly agreed upon rules in developing is to use 4 spaces for Python and 2 spaces for HTML and JavaScript/Typescript. I have even heard stories about developers leaving a presentation by someone from Google who showed Python code examples with 2 spaces 😱.</p><p>Most popular code formatters use 2 spaces or 4 spaces for indentation, preferring spaces over tabs to guarantee consistency across different text editors. Below is a breakdown of the standard spacing and indentation styles for the top 5 programming languages, driven by their industry-standard automated formatters.</p><h2>Standard Indentation by Language</h2><table><thead><tr><th style="text-align: left">Language</th><th style="text-align: left">Top Formatter</th><th style="text-align: left">Standard Indentation</th><th style="text-align: left">Common Spacing Rules</th></tr></thead><tbody><tr><td style="text-align: left">Python</td><td style="text-align: left">Black / Ruff</td><td style="text-align: left">4 Spaces</td><td style="text-align: left">Exactly 1 space around operators; 2 blank lines before top-level functions.</td></tr><tr><td style="text-align: left">JavaScript</td><td style="text-align: left">Prettier</td><td style="text-align: left">2 Spaces</td><td style="text-align: left">1 space before function parentheses; spaces inside object literal braces { foo: bar }.</td></tr><tr><td style="text-align: left">Java</td><td style="text-align: left">Google Java Formatter</td><td style="text-align: left">4 Spaces</td><td style="text-align: left">Spaces after keywords (if, for); braces open on the same line.</td></tr><tr><td style="text-align: left">TypeScript</td><td style="text-align: left">Prettier</td><td style="text-align: left">2 Spaces</td><td style="text-align: left">Identical to JavaScript; spaces inside type aliases and import statements.</td></tr><tr><td style="text-align: left">C#</td><td style="text-align: left">dotnet-format</td><td style="text-align: left">4 Spaces</td><td style="text-align: left">Spaces after commas and operators; braces open on a new line (Allman style).</td></tr></tbody></table><h2>Core Rules for Top Formatters</h2><ul><li><strong>Python (PEP 8):</strong> Avoids tabs entirely. Black strictly enforces 4 spaces and normalizes string quotes to double quotes.</li><li><strong>JavaScript/TypeScript (Prettier):</strong> Highly favors 2 spaces to keep deeply nested frontend code (like React JSX) highly readable without scrolling horizontally.</li><li><strong>Java (Google Style):</strong> While standard Java uses 4 spaces, the official Google Java Formatter tool defaults to 2 spaces. Most enterprise codebases still stick to 4 spaces.</li><li><strong>C# (Microsoft Style):</strong> Enforces 4 spaces. Unlike Java, curly braces must always occupy their own separate line.</li></ul>]]></content:encoded>
            <author>MsStryker</author>
            <category>indentation</category>
            <category>spacing</category>
            <category>formatters</category>
        </item>
        <item>
            <title><![CDATA[Did Asana Really Think It Would Take 5 Years?]]></title>
            <link>https://morgyn.io/post/asana-5-year-work</link>
            <guid isPermaLink="false">https://morgyn.io/post/asana-5-year-work</guid>
            <pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[OpenAI says it helped Asana replace a legacy test framework and cut costs from millions to thousands in two weeks. From experience rewriting systems, I have doubts.]]></description>
            <content:encoded><![CDATA[<p>A recent <a href="https://openai.com/index/asana/" target="_blank" rel="noopener noreferrer">post by OpenAI</a> claims to have cut costs for Asana from the estimated $6M to $12k in two weeks. I question that!</p><p>I have re-written a few systems and created systems from scratch and in all the scenarios, it took me weeks to a month or two (all depending on how many other projects or tasks I was juggling) to do this, and then a few weeks of QA to find any small bugs I may have missed. Depending on the complexity, the QA process always took longer than the development process. So, when a company claims a rewrite was needed at $6M, I question this. A frontend testing framework should not take that long to rewrite IMHO and should definitely not cost $6M. This exorbitant claim seems like there is more of a process or management issue at the company that is causing excessive bloat keeping them from iterating quickly.</p><p>I also question if the new system works as they expected if they only spent $12k doing it. With AI, we have been seeing many developers bypass the QA process entirely resulting in many more production bugs than we would normally see.</p><p>This article seems like hype to help with a pending IPO that may crash and burn when the finances are made clearer.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>opinion</category>
            <category>AI</category>
            <category>Asana</category>
            <category>OpenAI</category>
        </item>
        <item>
            <title><![CDATA[What IDE To Use]]></title>
            <link>https://morgyn.io/post/ides</link>
            <guid isPermaLink="false">https://morgyn.io/post/ides</guid>
            <pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A tour of the editors developers actually reach for — VS Code, the JetBrains family, Vim and Neovim, Cursor, Jupyter — and how to choose between them.]]></description>
            <content:encoded><![CDATA[<p>When I first learned to code, I was using a CRT computer monitor with green text on a black background similar to the Oregon Trail experience. I had to print out my programs with a dot matrix printer for my CS classes and I remember one day struggling with a program that appeared to be perfect, and I could not find the issue. I had to print out the code and go to my professor for help who almost immediatly circled in red the error. It was a C++ program that had a semicolon instead of a colon. 🤦</p><p>I really enjoyed CS, but it made me hate CS at the same time! Now, developing is so much easier, especially with AI.</p><p>I have used several different IDEs over the years and I am currently in VSCode, where my previous IDE of choice was PyCharm and anything JetBrains. The cost of VSCode is so much better than the JetBrains yearly fee.</p><p>One notibale IDE that is not listed below is <a href="https://zed.dev/" target="_blank" rel="noopener noreferrer">Zed</a>. It is "Your last next editor" and is a "minimal code editor crafted for speed and collaboration with humans and AI". For those who like using VSCode, this is an editor that may make you jump to something new. I may decide to switch to this IDE at some point for testing as speed is my goal. Most IDEs do not have an optimized terminal and I commonly have a terminal on the side for performance where I will occasionally use <code>vi</code>. I don't think I will ever fully give up the terminal experience. To me, it is so ingrained in my workflow.</p><h2>What IDE Do You Use?</h2><p>If you dare to ask ten developers which IDE to use and you get ten answers and one argument. So, rather than rank them by taste, this list follows the <a href="https://survey.stackoverflow.co/2025/technology" target="_blank" rel="noopener noreferrer">2025 Stack Overflow Developer Survey</a>, where over 25k developers said which IDE they actually used over the past year. The order below is theirs, not ours.</p><p>One clarification first, because the survey lumps them together and so does everyone else. A true <strong>IDE</strong> bundles an editor, a build system, a debugger, and language intelligence into one application that understands your project as a program — Visual Studio, IntelliJ, Android Studio. An <strong>editor</strong> opens files fast and gets the rest from plugins — Vim, Notepad++, and arguably VS Code. Half this list is technically the second category. That distinction has been eroding for a decade, mostly because the <a href="https://microsoft.github.io/language-server-protocol/" target="_blank" rel="noopener noreferrer">Language Server Protocol</a> let editors borrow the language smarts that used to justify an IDE's price tag.</p><p>The percentages are from a multi-select question, so they total far more than 100 percent. Most people use two or three.</p><h2>The Top 10</h2><ol><li><strong>Visual Studio Code</strong> — 75.9%</li><li><strong>Visual Studio</strong> — 29%</li><li><strong>Notepad++</strong> — 27.4%</li><li><strong>IntelliJ IDEA</strong> — 27.1%</li><li><strong>Vim</strong> — 24.3%</li><li><strong>Cursor</strong> — 17.9%</li><li><strong>PyCharm</strong> — 15%</li><li><strong>Android Studio</strong> — 15%</li><li><strong>Jupyter Notebook and JupyterLab</strong> — 14.1%</li><li><strong>Neovim</strong> — 14%</li></ol><h3>1. Visual Studio Code — 75.9%</h3><p>Three out of four developers. Nothing else in the survey comes close, and its nearest competitor is made by the same company.</p><p>It is an Electron app, which means it is heavier than a native editor and lighter than a real IDE, and it wins on the extension marketplace rather than on anything built in. The genuinely excellent parts are the remote development extensions — editing over SSH, inside a container, or in WSL, with the language server running on the remote machine and only the UI staying local. That workflow is hard to replicate elsewhere.</p><p>Worth knowing: the source is MIT-licensed as *Code - OSS*, but Microsoft's official builds add proprietary components, telemetry, and a marketplace whose terms only permit its use with Microsoft's own product. <a href="https://vscodium.com/" target="_blank" rel="noopener noreferrer">VSCodium</a> ships the same code without those, if that matters to you.</p><p><strong>Use it if</strong> you work across several languages, or you want the option to hire people who already know your tooling.</p><h3>2. Visual Studio — 29%</h3><p>Not the same product, despite the name. This is the full Windows IDE, and it is the strongest argument on this list that heavyweight IDEs still earn their weight. Its debugger — edit and continue, memory and performance profilers, IntelliTrace — is better than anything in the editor category, and for large C# and C++ codebases the difference is not subtle.</p><p>The catch is that it is Windows-only. Visual Studio for Mac was retired in August 2024, so Mac .NET work now means VS Code with the C# Dev Kit, or JetBrains Rider. The Community edition is free for individuals, open source work, and small organizations.</p><p><strong>Use it if</strong> you write .NET or serious C++ on Windows.</p><h3>3. Notepad++ — 27.4%</h3><p>The most interesting entry, because it is not an IDE at all and everyone knows it. It is a Scintilla-based text editor, Windows-only, GPL, and it opens a 500 MB log file instantly while your real editor is still thinking about it.</p><p>It ranks this high because "what do you use" and "what do you develop in" are different questions. Notepad++ is what is already installed for the config file, the SQL dump, the CSV someone emailed you. Its column-mode editing and find-in-files are still genuinely better than the equivalents in tools that cost money.</p><p><strong>Use it if</strong> you are on Windows and need to open something now.</p><h3>4. IntelliJ IDEA — 27.1%</h3><p>JetBrains built its reputation on static analysis, and IntelliJ is where it shows. Its refactorings are trustworthy in a way that text-based rename-and-hope is not, because it operates on a parsed model of your code rather than on strings. For a large Java or Kotlin codebase it remains the benchmark.</p><p>The cost is RAM and startup time, plus the licensing decision: Community edition is free and Apache-2.0, Ultimate is a subscription and holds the framework support most professional work needs. Nearly every other JetBrains IDE, including two on this list, is this platform with different plugins bundled.</p><p><strong>Use it if</strong> you write Java or Kotlin. It is not close.</p><h3>5. Vim — 24.3%</h3><p>A 1976 design in a 2025 top five. Vim's advantage is that it is *already there* — on the server, in the container, on the rescue disk — and its modal grammar of operators and motions is worth learning once for the rest of your career.</p><p>We wrote up the commands worth knowing in <a href="/post/vi-basics">the basics of vi</a>. Learn enough to edit a config file over SSH even if you never make it your daily driver; the alternative is being stranded on a box with no editor you can drive.</p><p><strong>Use it if</strong> you spend time on remote machines. Which is to say, use it.</p><h3>6. Cursor — 17.9%</h3><p>The newcomer, and the reason this list looks different from last year's. Cursor is a fork of VS Code with AI editing built into the core rather than bolted on — multi-file edits, codebase-aware chat, and inline completions that operate on more context than a single buffer.</p><p>Because it is a fork, your VS Code extensions, keybindings, and settings mostly carry over, which is exactly why it grew this fast. It is subscription-priced, it is a fork that must keep pace with its upstream, and the survey's own read is that the AI-native editors have not yet displaced the incumbents. Worth trying, worth not rebuilding your entire workflow around yet.</p><p><strong>Use it if</strong> you want AI assistance as the primary interface rather than an add-on panel.</p><h3>7. PyCharm — 15%</h3><p>IntelliJ's engine pointed at Python, and the difference from a generic editor is most obvious in the parts people underrate: the debugger, the test runner, and virtualenv handling that just works instead of requiring you to reason about which interpreter is active. Django, Flask, and FastAPI support is first-class in the paid tier.</p><p>Whether it beats VS Code with the Python and Pylance extensions is a real argument. PyCharm understands your project more deeply; VS Code starts faster and follows you into your other languages.</p><p><strong>Use it if</strong> Python is most of your work, especially on a large codebase.</p><h3>8. Android Studio — 15%</h3><p>Tied with PyCharm, and the least optional tool here. It is Google's IntelliJ-based IDE and effectively the only supported way to build Android apps — the emulator, layout inspector, APK analyzer, profilers, and Gradle integration are not meaningfully available elsewhere.</p><p>Nobody chooses Android Studio. They choose Android, and this comes with it. It is free.</p><p><strong>Use it if</strong> you ship Android.</p><h3>9. Jupyter Notebook and JupyterLab — 14.1%</h3><p>Also not an IDE, also not pretending to be. Notebooks interleave code, output, plots, and prose in a browser, which is the right shape for exploratory data work and for teaching — you see the result of each step next to the step.</p><p>The well-known trap is execution order: cells can run out of sequence, so a notebook that works on your screen may not work top-to-bottom on anyone else's. Restart-and-run-all before you share anything, and move code into real modules once it stops being an experiment.</p><p><strong>Use it if</strong> you are exploring data or explaining something. Not if you are shipping a service.</p><h3>10. Neovim — 14%</h3><p>The Vim fork that modernized the parts that needed it: Lua instead of Vimscript for configuration, a built-in LSP client, tree-sitter parsing for syntax and structural editing, and an async plugin architecture. Distributions like LazyVim get you a working setup in minutes rather than a weekend.</p><p>It is 10 points behind Vim, which is the honest summary — Vim is what is installed everywhere, Neovim is what people choose deliberately. Your muscle memory transfers completely.</p><p><strong>Use it if</strong> you already live in Vim and want language server features without a plugin archaeology project.</p><h2>What Changed Since Last Year</h2><p>Comparing against the <a href="https://survey.stackoverflow.co/2024/technology" target="_blank" rel="noopener noreferrer">2024 survey</a> is where the list gets interesting:</p><ul><li><strong>Cursor entered at number 6.</strong> It was not a listed option in 2024. That is the fastest arrival on this chart in years.</li><li><strong>Notepad++ passed IntelliJ IDEA</strong>, moving from 4th to 3rd on a jump from 23.9% to 27.4%.</li><li><strong>Vim and Neovim both gained</strong> — 21.6% to 24.3% and 12.5% to 14%. The terminal editors are not in decline, whatever the tooling discourse suggests.</li><li><strong>Sublime Text, Eclipse, and Xcode all dropped out of the top 10</strong>, having placed 10th, 11th, and 12th in 2024.</li><li><strong>VS Code and Visual Studio held the top two spots for the fourth consecutive year</strong>, a point the survey makes itself when noting that AI-enabled subscription IDEs have not toppled them.</li></ul><p>One honest caveat on those comparisons: the 2024 IDE question had 58,121 respondents against 2025's 26,143. Different sample sizes and a different respondent mix mean small movements are noise. Cursor arriving at 17.9% is a real signal; Notepad++ gaining 3.5 points may not be.</p><h2>How To Actually Choose</h2><p>The survey tells you what is popular, not what is right for you. A shorter decision:</p><ul><li><strong>Your ecosystem has an obvious answer — take it.</strong> Android means Android Studio, iOS means Xcode, large Java means IntelliJ, .NET on Windows means Visual Studio. Fighting this costs you tooling that took a decade to build.</li><li><strong>No obvious answer? Start with VS Code.</strong> Its ubiquity is a feature: extensions exist for everything, and every problem you hit has been answered already.</li><li><strong>Learn Vim's basics regardless of your daily driver.</strong> It is a portable skill, not a choice of allegiance.</li><li><strong>Try a JetBrains IDE once on a large codebase.</strong> If you have only ever used editors, the refactoring and analysis are worth feeling directly before you form an opinion about whether IDEs are bloated.</li><li><strong>Optimize the debugger, not the theme.</strong> Time spent learning conditional breakpoints and watch expressions pays back permanently; time spent on your color scheme does not.</li></ul><p>The uncomfortable truth is that the tool matters much less than knowing it well. A developer fluent in Notepad++ and a terminal will out-ship someone who reconfigures their editor every weekend, and there is at least one of those on every team.</p><h2>A Note On The Data</h2><p>The Stack Overflow survey is the best public dataset on this, and it is still a self-selected sample of people who use Stack Overflow. It skews toward web development, and toward English-speaking respondents. Read the percentages as "widely used by developers like the ones who answer this survey," which is not quite the same as the profession as a whole. Numbers here are from the 2025 and 2024 editions and will move.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>ide</category>
            <category>vscode</category>
            <category>pycharm</category>
            <category>jetbrains</category>
            <category>visual studio</category>
            <category>notepad++</category>
            <category>intelliJ</category>
            <category>vim</category>
            <category>cursor</category>
            <category>android studio</category>
            <category>jupyter notebook</category>
            <category>neovim</category>
        </item>
        <item>
            <title><![CDATA[My Daily Reading]]></title>
            <link>https://morgyn.io/post/hacker-news</link>
            <guid isPermaLink="false">https://morgyn.io/post/hacker-news</guid>
            <pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A beige page of links that has outlasted every prettier competitor. How Hacker News ranking, karma thresholds, moderation, and its free public API work.]]></description>
            <content:encoded><![CDATA[<p><a href="https://news.ycombinator.com/" target="_blank" rel="noopener noreferrer">Hacker News</a> is a beige table of thirty links with no images, no infinite scroll, and no algorithmic feed tuned to your interests. Paul Graham launched it on February 19, 2007 as Startup News, renamed it that August, and it still runs on <strong>Arc</strong> — a Lisp dialect he wrote himself. It has outlasted a long parade of better-looking competitors, and it is owned and operated by Y Combinator.</p><p>It is worth understanding as a system, not just a website. Almost everything that feels arbitrary about it — why your submission vanished, why a two-point comment sits above a forty-point one, why nobody has a downvote arrow — is a documented rule.</p><h2>What Gets on the Front Page</h2><p>The official answer from the FAQ is deliberately vague: "the basic algorithm divides points by a power of the time since a story was submitted." That decay is the whole personality of the site. A story with 40 points from twenty minutes ago outranks one with 200 points from yesterday, so the front page turns over several times a day and nothing camps at the top.</p><p>Because the ranking code has been open source at various points, the shape of it is well known — points minus one, divided by hours-since-submission plus a small offset, raised to a power somewhere near 1.8. Do not treat that as gospel. What matters is the behavior: <strong>velocity beats volume</strong>, and time punishes everything.</p><p>Layered on top of the arithmetic are several things that quietly override it:</p><ul><li><strong>User flags</strong>, which can sink a story without a moderator touching it</li><li><strong>Anti-abuse software</strong> watching for voting rings and manipulation</li><li><strong>Automatic demotion of heated discussions</strong> — a flamewar penalty on comment-heavy threads</li><li><strong>Per-account and per-domain weighting</strong>, so not all upvotes count equally</li><li><strong>Moderator action</strong>, which is human, visible, and frequently explained in the thread</li></ul><p>Daniel Gackle (<code>dang</code>) and Tom Howard (<code>tomhow</code>) do that moderating. It is unusual for a site this size to be moderated by people who reply to complaints under their own usernames, and it is a large part of why the comment sections still function.</p><p>There is also a <strong>second chance pool</strong>: good submissions that landed at a bad hour get re-queued for another shot at the front page rather than being lost to timing.</p><h2>The Karma Thresholds</h2><p>Karma is "roughly, the number of upvotes on their posts minus the number of downvotes." It buys almost nothing — no badges, no flair — but it does unlock the moderation tools, and the numbers are specific:</p><ul><li><strong>30 karma</strong> — you can flag comments</li><li><strong>501 karma</strong> — the downvote arrow appears on comments</li></ul><p>Two rules surprise people. There are <strong>no downvotes on stories at all</strong>, ever, at any karma level; flagging is the only way to push a submission down. And you cannot downvote a direct reply to your own comment, which neatly removes the temptation to bury someone who disagreed with you.</p><p>A few other mechanics worth knowing:</p><ul><li><strong>Dead posts</strong> are hidden by default. Turn on <code>showdead</code> in your profile to see them, which is genuinely educational about what the site filters.</li><li><strong>Vouching</strong> rescues a dead post that should not be dead — open the post's own page via its timestamp and click <code>vouch</code>. Enough vouches restore it.</li><li><strong>Shadowbanning</strong> is real: a banned account's posts stay invisible to everyone else while looking normal to the author. If your submissions get zero engagement forever, that is worth ruling out.</li></ul><h2>Submitting Without Annoying Everyone</h2><p>The <a href="https://news.ycombinator.com/newsguidelines.html" target="_blank" rel="noopener noreferrer">guidelines</a> are short and mostly about restraint. The submission rules that actually get enforced:</p><ul><li><strong>Submit the original source</strong>, not a blog reporting on the original source</li><li><strong>Use the real title.</strong> Do not editorialize, do not add your own spin</li><li><strong>Strip the site name</strong> from the title — it is displayed automatically</li><li><strong>Cut gratuitous numbers.</strong> "10 Ways to Do X" becomes "How to Do X"</li><li><strong>Tag the format</strong> with <code>[video]</code> or <code>[pdf]</code> so people know what they are clicking</li><li><strong>Never ask for upvotes</strong>, and never delete-and-repost to reroll the timing</li></ul><p>On-topic is defined as "anything that gratifies one's intellectual curiosity" — which in practice means most politics, crime, sports, and celebrity stories are off-topic unless they reveal some genuinely new phenomenon. The rule of thumb: if TV news would cover it, it probably does not belong.</p><p>The post types are worth using deliberately:</p><ul><li><strong>Show HN</strong> — your own working project, something people can actually try. Has its own extra rules; read them before posting.</li><li><strong>Ask HN</strong> — a question to the community, as a text post with no URL.</li><li><strong>Tell HN</strong> — an announcement or piece of information rather than a question.</li><li><strong>Launch HN</strong> — reserved for YC companies announcing themselves, arranged with the mods.</li><li><strong>Who is Hiring</strong> — a monthly thread posted by a bot on the first weekday of the month, and one of the better places to find engineering work without a recruiter in the middle.</li></ul><p>Note that Show HN and Ask HN submissions land on <code>/newest</code> first and need points before they appear on the curated <code>/show</code> and <code>/ask</code> pages. Nothing skips the queue.</p><h2>Commenting Culture</h2><p>The comment guidelines read like a style guide for arguing well, and the moderators enforce them:</p><ul><li><strong>Be kind.</strong> Do not be snarky. Sneering is explicitly called out.</li><li><strong>Respond to the strongest interpretation</strong> of what someone said, not the weakest.</li><li><strong>Address arguments, not people</strong>, and assume good faith.</li><li><strong>No shallow dismissals</strong> of other people's work — the drive-by "this is useless" comment.</li><li><strong>No comments about voting</strong> or about whether someone read the article.</li><li><strong>No generic tangents</strong> or worn internet tropes.</li><li><strong>Flag spam</strong> instead of replying to it.</li><li><strong>No generated or AI-edited text.</strong> The guidelines now say this outright, which is a real constraint if you were planning to paste a model's output into a thread.</li></ul><p>Comments are not sorted purely by score, and threads that get heated get actively demoted. That is intentional: the site optimizes for a discussion still being worth reading a week later, not for engagement.</p><h2>The API Is Free and Genuinely Good</h2><p>For developers this is the fun part. Hacker News exposes a read-only <a href="https://github.com/HackerNews/API" target="_blank" rel="noopener noreferrer">Firebase-backed API</a> with **no authentication and no rate limit**, which makes it one of the easiest real datasets to build against.</p><p>The base URL:</p><pre><code>https://hacker-news.firebaseio.com/v0
</code></pre><p>The endpoints you will actually use:</p><ul><li><code>/topstories.json</code> — up to 500 ids, front-page order, jobs included</li><li><code>/newstories.json</code> — up to 500 ids, newest first</li><li><code>/beststories.json</code> — the highest-scoring recent stories</li><li><code>/askstories.json</code>, <code>/showstories.json</code>, <code>/jobstories.json</code> — up to 200 ids each</li><li><code>/item/ID.json</code> — one story, comment, poll, or job by id</li><li><code>/user/NAME.json</code> — a profile</li><li><code>/maxitem.json</code> — the largest id currently in use</li><li><code>/updates.json</code> — items and profiles that changed recently</li></ul><p>Append <code>?print=pretty</code> to get indented JSON in a browser:</p><pre><code>curl -s "https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty"
</code></pre><p>The important design detail: the list endpoints return <strong>ids only</strong>, so you fetch each item separately. Everything is one flat item type — stories, comments, jobs and polls all come back from <code>/item/ID.json</code>, distinguished by a <code>type</code> field.</p><pre><code>const BASE = 'https://hacker-news.firebaseio.com/v0'

const ids = await fetch(`${BASE}/topstories.json`).then((r) => r.json())

const stories = await Promise.all(
  ids.slice(0, 10).map((id) => fetch(`${BASE}/item/${id}.json`).then((r) => r.json()))
)

for (const story of stories) {
  console.log(story.score, story.title, story.url)
}
</code></pre><p>An item carries <code>id</code>, <code>type</code>, <code>by</code>, <code>time</code>, <code>title</code>, <code>url</code>, <code>text</code>, <code>score</code>, <code>parent</code>, <code>kids</code> (child comment ids), <code>descendants</code> (total comment count), plus <code>deleted</code> and <code>dead</code> flags. A user carries <code>id</code>, <code>created</code>, <code>karma</code>, <code>about</code>, and <code>submitted</code>.</p><p>Two things to know before you build. Comment trees come as <code>kids</code> arrays, so rendering a full thread means recursively fetching every id — that is a lot of requests for a big discussion, and the reason most clients cache aggressively. And <code>time</code> is a **Unix timestamp in seconds**, not milliseconds, so multiply by 1000 before handing it to <code>new Date</code>.</p><p>For full-text search, the API cannot do it, but Algolia's index — the same one behind the site's own search box — can:</p><pre><code>curl -s "https://hn.algolia.com/api/v1/search?query=postgres"
</code></pre><h2>Surviving the Front Page</h2><p>If something you built lands on it, the traffic arrives in minutes, not hours. Serve the page statically if you can, put a CDN in front of it, and make sure the thing you are demoing is not doing real work per request. The classic outcome is a project getting its one big moment of attention and returning a 502 for it.</p><p>Then go read the comments. A front-page thread is a free technical review from people who will find the flaw in your approach within the hour, which is uncomfortable and much more useful than praise.</p><h2>Reading It Well</h2><p>Sort by curiosity rather than by outrage, and it stays a good site for a long time. A few habits help: <code>/best</code> is a better front page than <code>/</code> if you visit occasionally, <code>/newest</code> is where you find things before they are popular, and the comments on a story are frequently better than the story.</p><p>Turn on <code>showdead</code> for a week. Read the <a href="https://news.ycombinator.com/newsguidelines.html" target="_blank" rel="noopener noreferrer">guidelines</a> once, properly. And when you are about to post something sharp, remember that the strongest version of the argument you are replying to is the one the site expects you to answer.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>hacker news</category>
            <category>community</category>
            <category>api</category>
        </item>
        <item>
            <title><![CDATA[Getting started with Oh My Zsh]]></title>
            <link>https://morgyn.io/post/oh-my-zsh</link>
            <guid isPermaLink="false">https://morgyn.io/post/oh-my-zsh</guid>
            <pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Oh My Zsh turns a bare Zsh shell into a productive terminal in one command. How to install it, choose a theme, and enable the plugins actually worth having.]]></description>
            <content:encoded><![CDATA[<p><a href="https://ohmyz.sh/" target="_blank" rel="noopener noreferrer">Oh My Zsh</a> calls itself "a delightful, open source, community-driven framework for managing your Zsh configuration". It makes your terminal much more useful than the standard settings. It is a directory of shell code that loads on startup and gives you a good prompt, several hundred optional plugins, and a pile of aliases you did not have to write. Robby Russell started it at Planet Argon; it is now maintained by Marc Cornellà and Carlo Sala, and it is MIT licensed.</p><p>It will not make you a 10x developer, but people do report being more comfortable in a terminal afterward.</p><h2>Before You Install</h2><p>Oh My Zsh configures Zsh — it does not install it. Check that you have the shell first:</p><pre><code>zsh --version
</code></pre><p>macOS has shipped Zsh as the default login shell since Catalina, so you are probably set. On Linux, install <code>zsh</code> from your package manager. If Zsh is installed but not your login shell, switch it:</p><pre><code>chsh -s $(which zsh)
</code></pre><p>Log out and back in for that to take effect.</p><h2>Installing</h2><p>Either of these will do it — pick whichever tool you have:</p><pre><code>sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
</code></pre><pre><code>sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
</code></pre><p>There is also a shortened mirror, <code>https://install.ohmyz.sh/</code>, useful in regions where raw.githubusercontent.com is blocked.</p><p>Both of these pipe a remote script straight into a shell. That is the project's documented install path and the script is short and readable, but the habit is worth resisting in general — download it, skim it, then run it if you would rather see what you are executing.</p><p>A few things happen during install:</p><ul><li>The repository is cloned to <code>~/.oh-my-zsh</code></li><li>Your existing <code>~/.zshrc</code> is backed up to <code>~/.zshrc.pre-oh-my-zsh</code></li><li>A new <code>~/.zshrc</code> is written from the project's template</li></ul><p>That backup matters. Your old configuration is not gone, and if you decide Oh My Zsh is not for you, the uninstaller puts it back.</p><p>If you are scripting the install and do not want it to change your shell or start an interactive session, pass <code>--unattended</code>.</p><h2>What Lives in .zshrc</h2><p>Almost everything you will tune is in <code>~/.zshrc</code>, and two lines do most of the work:</p><ul><li><code>ZSH_THEME="robbyrussell"</code> — the prompt, set to the default theme</li><li><code>plugins=(git)</code> — the enabled plugins</li></ul><p>Your own aliases, exports, and functions go at the bottom of that file. Anything larger belongs in <code>$ZSH_CUSTOM</code>, which defaults to <code>~/.oh-my-zsh/custom</code> and is the one directory an update will never overwrite. Put custom themes in <code>custom/themes/</code> and any <code>.zsh</code> file in <code>custom/</code> to have it sourced automatically.</p><p>After editing, reload the shell with <code>omz reload</code> or by opening a new tab.</p><h2>Plugins</h2><p>Plugins are enabled by listing their names in the <code>plugins</code> array — whitespace separated, <strong>no commas</strong>, which is the single most common mistake:</p><pre><code>plugins=(git docker kubectl npm z sudo extract)
</code></pre><p>The bundled set runs past 300 and covers most of what a working day touches. A few worth knowing:</p><ul><li><strong>git</strong> — enabled by default, and the reason most people stay. <code>gst</code> for status, <code>ga</code> to add, <code>gc</code> to commit, <code>gco</code> to check out, <code>gcb</code> to check out a new branch, <code>gd</code> to diff, <code>gp</code> to push, <code>gl</code> to pull, <code>glog</code> for a graph log.</li><li><strong>z</strong> — jumps to directories you visit often by fuzzy name, so <code>z morgyn</code> beats four <code>cd ..</code> in a row.</li><li><strong>sudo</strong> — press <code>Esc</code> twice to prepend <code>sudo</code> to the command you just typed, or to the last one you ran.</li><li><strong>extract</strong> — one <code>extract</code> command that handles tar, zip, gz, bz2, xz, 7z and friends so you stop looking up flags.</li><li><strong>docker</strong>, <strong>kubectl</strong>, <strong>npm</strong>, <strong>python</strong> — completions and short aliases for tools whose own commands are long.</li><li><strong>command-not-found</strong> — suggests the package to install when you mistype a binary.</li><li><strong>macos</strong> — Finder and system helpers, on macOS only.</li></ul><p>Run <code>omz plugin list</code> to see everything available.</p><p>Two plugins that everyone recommends are <strong>not</strong> bundled, because they live in separate repositories — <code>zsh-autosuggestions</code>, which ghosts your next command from history, and <code>zsh-syntax-highlighting</code>, which colors your command line as you type. Clone them into <code>$ZSH_CUSTOM</code> and add them to the array:</p><pre><code>git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
</code></pre><p>List <code>zsh-syntax-highlighting</code> <strong>last</strong> in <code>plugins</code>. It hooks the line editor and expects to be loaded after everything else.</p><h2>Themes</h2><p>Over 150 themes ship with it. <code>robbyrussell</code> is the default and stays out of your way; <code>agnoster</code> is the well-known one with the segmented arrow prompt, though it needs a Powerline or Nerd Font installed or the glyphs render as boxes.</p><p>Set one directly:</p><pre><code>omz theme use agnoster
</code></pre><p>To browse, set <code>ZSH_THEME="random"</code> and open new shells until something appeals — the name of the active theme is in <code>$RANDOM_THEME</code>. If you want the popular <a href="https://github.com/romkatv/powerlevel10k" target="_blank" rel="noopener noreferrer">Powerlevel10k</a>, it is a separate project you clone into <code>custom/themes/</code> rather than a bundled option.</p><h2>Keeping It Updated</h2><pre><code>omz update
</code></pre><p>Oh My Zsh also checks for updates on its own. Control that with a <code>zstyle</code> line in <code>.zshrc</code>:</p><ul><li><code>zstyle ':omz:update' mode auto</code> — update silently in the background</li><li><code>zstyle ':omz:update' mode reminder</code> — only tell you an update exists</li><li><code>zstyle ':omz:update' mode disabled</code> — never check</li><li><code>zstyle ':omz:update' frequency 13</code> — days between checks</li></ul><h2>When Your Shell Feels Slow</h2><p>The honest tradeoff: every plugin is shell code that runs at startup, and thirty of them are noticeable. Time a fresh interactive shell:</p><pre><code>time zsh -i -c exit
</code></pre><p>Anything past a few hundred milliseconds is usually one expensive plugin — the version managers and cloud CLIs are the usual suspects. Bisect the <code>plugins</code> array, and only keep what you actually use. Enabling a plugin for a tool you touch twice a year costs you on every single shell you open.</p><h2>Uninstalling</h2><pre><code>uninstall_oh_my_zsh
</code></pre><p>That removes <code>~/.oh-my-zsh</code> and restores the <code>.zshrc</code> the installer backed up. Clean exit, which is a good sign in a tool that rewrites your shell config.</p><h2>Worth It?</h2><p>If you live in a terminal, yes — mostly for the git aliases, the two external plugins above, and a prompt that shows your branch without you configuring anything. It is a config framework rather than magic, and the useful move after installing is to open <code>~/.zshrc</code>, read it, and delete the parts you do not want.</p><p>The <a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins" target="_blank" rel="noopener noreferrer">plugin list</a> and <a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes" target="_blank" rel="noopener noreferrer">themes gallery</a> on the project wiki are the best places to browse from here.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>zsh</category>
            <category>shell</category>
            <category>terminal</category>
        </item>
        <item>
            <title><![CDATA[The basics of vi]]></title>
            <link>https://morgyn.io/post/vi-basics</link>
            <guid isPermaLink="false">https://morgyn.io/post/vi-basics</guid>
            <pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[vi has shipped on nearly every Unix machine for 50 years. Learn the few modes and commands that mean you are never stranded on a server without an editor.]]></description>
            <content:encoded><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Bill_Joy" target="_blank" rel="noopener noreferrer">Bill Joy</a> wrote <a href="https://en.wikipedia.org/wiki/Vi_(text_editor)" target="_blank" rel="noopener noreferrer">vi in 1976</a>, and fifty years later it is still on nearly every machine you will ever log into. Servers, containers, embedded devices, rescue disks — if there is a shell, there is almost always a <code>vi</code>. Learning a handful of commands means you are never stranded on a box without a usable editor.</p><p>Most systems today ship <strong>vim</strong> ("vi improved") or <strong>nvim</strong> aliased to <code>vi</code>. Everything below works in all of them.</p><h2>Modal Editing</h2><p>The idea that trips up newcomers is that vi is <strong>modal</strong>. Keys do different things depending on the mode you are in.</p><ul><li><strong>Normal mode</strong> — where you start. Keys are commands, not text. <code>x</code> deletes a character.</li><li><strong>Insert mode</strong> — keys type text, like any other editor. Enter with <code>i</code>, leave with <code>Esc</code>.</li><li><strong>Command-line mode</strong> — entered with <code>:</code>, used for saving, quitting, and search-and-replace.</li><li><strong>Visual mode</strong> — entered with <code>v</code>, used to select a range of text.</li></ul><p>When in doubt, press <code>Esc</code>. It always returns you to normal mode, and pressing it twice is harmless.</p><h2>Opening and Saving</h2><ul><li><code>vi notes.txt</code> — open a file, creating it if it does not exist</li><li><code>vi +42 notes.txt</code> — open the file at line 42</li><li><code>:w</code> — write (save) the file</li><li><code>:w other.txt</code> — write to a different filename</li><li><code>:q</code> — quit</li><li><code>:wq</code> — write and quit</li><li><code>:x</code> — write and quit, but only writes if something changed</li><li><code>:q!</code> — quit and throw away all changes</li><li><code>:e!</code> — reload the file from disk, discarding changes</li></ul><p>The classic "how do I get out of vi" answer is <code>Esc</code> followed by <code>:q!</code> and <code>Enter</code>. If the file is read-only and you have <code>sudo</code> rights, <code>:w !sudo tee %</code> writes it anyway.</p><h2>Moving Around</h2><p>The home-row keys move the cursor so your hands never leave their resting position. Arrow keys work too, but the habit is worth building.</p><ul><li><code>h</code> <code>j</code> <code>k</code> <code>l</code> — left, down, up, right</li><li><code>w</code> — forward to the start of the next word; <code>b</code> — back a word; <code>e</code> — end of word</li><li><code>0</code> — start of the line; <code>^</code> — first non-blank character; <code>$</code> — end of the line</li><li><code>gg</code> — top of the file; <code>G</code> — bottom of the file; <code>42G</code> — go to line 42</li><li><code>Ctrl-f</code> / <code>Ctrl-b</code> — page forward / back</li><li><code>Ctrl-d</code> / <code>Ctrl-u</code> — half page down / up</li><li><code>{</code> / <code>}</code> — previous / next blank line, handy for jumping between paragraphs</li><li><code>%</code> — jump to the matching bracket, paren, or brace</li></ul><h2>Entering Insert Mode</h2><p>Where you enter insert mode from matters, and picking the right key saves a lot of cursor nudging.</p><ul><li><code>i</code> — insert before the cursor; <code>a</code> — append after the cursor</li><li><code>I</code> — insert at the first non-blank character of the line</li><li><code>A</code> — append at the end of the line</li><li><code>o</code> — open a new line below and insert; <code>O</code> — open a new line above</li><li><code>cw</code> — change a word: deletes to the end of the word and drops into insert mode</li><li><code>C</code> — change from the cursor to the end of the line</li></ul><h2>Editing Text</h2><p>Most editing commands follow the pattern <strong>operator + motion</strong>. <code>d</code> is the delete operator, <code>w</code> is the word motion, so <code>dw</code> deletes a word. Once you see the pattern, the commands multiply on their own.</p><ul><li><code>x</code> — delete the character under the cursor</li><li><code>dw</code> — delete to the start of the next word</li><li><code>dd</code> — delete the whole line; <code>3dd</code> — delete three lines</li><li><code>D</code> — delete from the cursor to the end of the line</li><li><code>yy</code> — yank (copy) the current line; <code>3yy</code> — yank three lines</li><li><code>yw</code> — yank a word</li><li><code>p</code> — paste after the cursor; <code>P</code> — paste before</li><li><code>r</code> — replace a single character; <code>R</code> — overwrite until <code>Esc</code></li><li><code>J</code> — join the line below onto the current line</li><li><code>u</code> — undo; <code>Ctrl-r</code> — redo</li><li><code>.</code> — repeat the last change, the single biggest time-saver in vi</li></ul><p>Numbers repeat commands, so <code>5j</code> moves down five lines and <code>10x</code> deletes ten characters. Combine that with <code>.</code> and repetitive edits get very fast.</p><h2>Searching and Replacing</h2><ul><li><code>/pattern</code> — search forward; <code>?pattern</code> — search backward</li><li><code>n</code> — next match; <code>N</code> — previous match</li><li><code>*</code> — search for the word under the cursor</li><li><code>:noh</code> — clear the highlighting left behind by a search</li><li><code>:s/old/new/</code> — replace the first match on the current line</li><li><code>:s/old/new/g</code> — replace every match on the current line</li><li><code>:%s/old/new/g</code> — replace every match in the whole file</li><li><code>:%s/old/new/gc</code> — same, but confirm each replacement</li><li><code>:%s/old/new/gi</code> — same, case-insensitive</li></ul><p>The <code>%</code> means "all lines," <code>g</code> means "all matches on each line," and <code>c</code> means "confirm." Read <code>:%s/old/new/gc</code> as *in the whole file, replace old with new everywhere, asking me first*.</p><h2>Visual Mode</h2><ul><li><code>v</code> — start a character selection; move to grow it</li><li><code>V</code> — select whole lines</li><li><code>Ctrl-v</code> — block (column) selection, good for editing aligned text</li><li><code>d</code> — delete the selection; <code>y</code> — yank it; <code>></code> or <code><</code> — indent or unindent</li><li><code>gv</code> — reselect whatever you last had selected</li></ul><h2>Useful Settings</h2><p>Type these with <code>:</code> for the current session, or put them in <code>~/.vimrc</code> without the colon to make them permanent.</p><ul><li><code>:set number</code> — show line numbers</li><li><code>:set ignorecase</code> — case-insensitive searching</li><li><code>:set hlsearch</code> — highlight search matches</li><li><code>:set expandtab</code> and <code>:set shiftwidth=2</code> — insert two spaces instead of tabs</li><li><code>:set paste</code> — stop auto-indent from mangling text you paste in</li><li><code>:syntax on</code> — enable syntax highlighting</li></ul><h2>Working With Several Files</h2><ul><li><code>:e other.txt</code> — edit another file</li><li><code>:bn</code> / <code>:bp</code> — next / previous buffer; <code>:ls</code> — list open buffers</li><li><code>:sp file</code> — split horizontally; <code>:vsp file</code> — split vertically</li><li><code>Ctrl-w</code> then <code>w</code> — cycle between splits</li><li><code>:diffthis</code> in two splits — show a diff between them</li></ul><h2>A Short Practice Session</h2><p>Muscle memory beats memorization. Open a scratch file and run through this once or twice:</p><ol><li><code>vi scratch.txt</code> then <code>i</code>, type a few lines, then press <code>Esc</code>.</li><li><code>gg</code> to the top, <code>dd</code> to delete a line, <code>u</code> to bring it back.</li><li><code>/word</code> and <code>Enter</code> to find something, then <code>n</code> to walk the matches.</li><li><code>cw</code> to change the word under the cursor, <code>Esc</code>, then <code>.</code> to repeat it elsewhere.</li><li><code>:%s/old/new/g</code> to rename something everywhere.</li><li><code>:wq</code> to save and quit.</li></ol><p>That is genuinely enough to be productive. Everything else — macros, registers, marks, <code>:g/pattern/</code>, plugins — builds on the same operator-plus-motion grammar you already learned. If you want to go deeper, run <code>vimtutor</code> from your terminal for a hands-on twenty-minute walkthrough.</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>vi</category>
            <category>text editor</category>
        </item>
        <item>
            <title><![CDATA[Launch Day!]]></title>
            <link>https://morgyn.io/post/first-post</link>
            <guid isPermaLink="false">https://morgyn.io/post/first-post</guid>
            <pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Introducing Morgyn IO — a growing collection of free developer tools, browser games, tutorials, and honest opinions on modern web development.]]></description>
            <content:encoded><![CDATA[<p>We are excited to launch this site!</p><p>Here we will add resources, games, tools, resources, educational content, and opinions on the latest technologies. We enjoy learning and coding and are excited to share what we know with you.</p><p>We have added some common tools that we use daily in one spot, such as:</p><ul><li><a href="/tools/json-pretty-printer">JSON Pretty Printer</a></li><li><a href="/tools/xml-pretty-printer">XML Pretty Printer</a></li><li><a href="/tools/lorem-ipsum">Lorem Ipsum Generator</a></li><li>IP address is in the footer</li><li>UTC timestamp in the footer</li></ul><p>Stay tuned for more details and enhancements to this site.</p><p>P.S. In true developer form, the authors will be linked with their GitHub handles!</p>]]></content:encoded>
            <author>MsStryker</author>
            <category>init</category>
            <category>launch</category>
        </item>
    </channel>
</rss>