<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Skerritt.blog]]></title><description><![CDATA[Esoteric Computer Science Knowledge from your favourite local trans rust girlie ]]></description><link>https://skerritt.blog/</link><image><url>https://skerritt.blog/favicon.png</url><title>Skerritt.blog</title><link>https://skerritt.blog/</link></image><generator>Ghost 5.79</generator><lastBuildDate>Tue, 20 Feb 2024 08:22:08 GMT</lastBuildDate><atom:link href="https://skerritt.blog/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[The Ultimate Discord Hacking Bot]]></title><description><![CDATA[<p>The Ultimate Hacking Bot&#x2122;&#xFE0F; contains a bunch of useful hacking tools:</p><ul><li><a href="https://github.com/swanandx/lemmeknow?ref=skerritt.blog">LemmeKnow</a></li><li><a href="https://github.com/bee-san/ares?ref=skerritt.blog">Ares</a></li><li><a href="https://github.com/Ciphey/Ciphey?ref=skerritt.blog">Ciphey</a></li><li><a href="https://github.com/HashPals/Search-That-Hash?ref=skerritt.blog">Search-That-Hash</a></li></ul><p>The GitHub Link is below:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/bee-san/discord-bot?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - bee-san/discord-bot: Discord bot for Ares &amp; Lemmeknow in the http://discord.skerritt.blog discord server</div><div class="kg-bookmark-description">Discord bot for Ares &amp;amp; Lemmeknow in the http:</div></div></a></figure>]]></description><link>https://skerritt.blog/the-ultimate-discord-hacking-bot/</link><guid isPermaLink="false">6572ee9e4c102d0001474077</guid><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Fri, 08 Dec 2023 10:39:17 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1682687220795-796d3f6f7000?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wxfDF8YWxsfDF8fHx8fHwyfHwxNzAyMDI5NzE5fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1682687220795-796d3f6f7000?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wxfDF8YWxsfDF8fHx8fHwyfHwxNzAyMDI5NzE5fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The Ultimate Discord Hacking Bot"><p>The Ultimate Hacking Bot&#x2122;&#xFE0F; contains a bunch of useful hacking tools:</p><ul><li><a href="https://github.com/swanandx/lemmeknow?ref=skerritt.blog">LemmeKnow</a></li><li><a href="https://github.com/bee-san/ares?ref=skerritt.blog">Ares</a></li><li><a href="https://github.com/Ciphey/Ciphey?ref=skerritt.blog">Ciphey</a></li><li><a href="https://github.com/HashPals/Search-That-Hash?ref=skerritt.blog">Search-That-Hash</a></li></ul><p>The GitHub Link is below:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/bee-san/discord-bot?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - bee-san/discord-bot: Discord bot for Ares &amp; Lemmeknow in the http://discord.skerritt.blog discord server</div><div class="kg-bookmark-description">Discord bot for Ares &amp;amp; Lemmeknow in the http://discord.skerritt.blog discord server - GitHub - bee-san/discord-bot: Discord bot for Ares &amp;amp; Lemmeknow in the http://discord.skerritt.blog disc&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt="The Ultimate Discord Hacking Bot"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">bee-san</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/d3b869d7697f29809ebba2c8fb6d1ecd3d9e7cefde89ab9a02deb18a9ed1502d/bee-san/discord-bot" alt="The Ultimate Discord Hacking Bot"></div></a></figure><h1 id="using-the-bot">Using the bot</h1><p>Go to <a href="http://discord.skerritt.blog/?ref=skerritt.blog" rel="noreferrer">http://discord.skerritt.blog</a> , join and use the bot in the #bots channel with <code>$help</code>.</p><h1 id="installing-on-your-own-server">Installing on your own server</h1><p>You can either use the docker image created <code>autumnskerritt/discord_bot</code>, or you could build your own Docker image or you could run <code>cargo run .</code> to run the bot.</p><p>You can also install my instance of the bot with the below link:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://discord.com/api/oauth2/authorize?client_id=1047524231400923206&amp;permissions=277025467456&amp;scope=bot&amp;ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Discord - A New Way to Chat with Friends &amp; Communities</div><div class="kg-bookmark-description">Discord is the easiest way to communicate over voice, video, and text. Chat, hang out, and stay close with your friends and communities.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://discord.com/assets/images/favicon.ico" alt="The Ultimate Discord Hacking Bot"><span class="kg-bookmark-author">Discord</span></div></div></a></figure><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4D4;</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">NOTE</strong></b>: I do not guarantee 100% uptime as I am providing this free of service.</div></div>]]></content:encoded></item><item><title><![CDATA[How we keep our self-hosted Discord bot up to date]]></title><description><![CDATA[<p>Over in my <a href="http://discord.skerritt.blog/?ref=skerritt.blog">Discord</a> we have a cool bot called &#x2728;The Ultimate Hacking Bot&#x2728;</p>
<p>Really it&apos;s a bot that has a collection of pentesting tools one may find useful.</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/08/ares-bot.gif" class="kg-image" alt loading="lazy" width="800" height="525" srcset="https://skerritt.blog/content/images/size/w600/2023/08/ares-bot.gif 600w, https://skerritt.blog/content/images/2023/08/ares-bot.gif 800w" sizes="(min-width: 720px) 720px"></figure>
<p>With many tools come many issues... Dependency issues...</p>
<p>If one of our many dependencies updated, our process</p>]]></description><link>https://skerritt.blog/how-we-keep-our-discord-bot-up-to-date/</link><guid isPermaLink="false">64d7430e1be1810001128c54</guid><category><![CDATA[self-hosted]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Sat, 12 Aug 2023 10:07:24 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1691415058595-d18acf8bd102?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8YWxsfDl8fHx8fHwyfHwxNjkxODM0NTg1fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1691415058595-d18acf8bd102?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8YWxsfDl8fHx8fHwyfHwxNjkxODM0NTg1fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="How we keep our self-hosted Discord bot up to date"><p>Over in my <a href="http://discord.skerritt.blog/?ref=skerritt.blog">Discord</a> we have a cool bot called &#x2728;The Ultimate Hacking Bot&#x2728;</p>
<p>Really it&apos;s a bot that has a collection of pentesting tools one may find useful.</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/08/ares-bot.gif" class="kg-image" alt="How we keep our self-hosted Discord bot up to date" loading="lazy" width="800" height="525" srcset="https://skerritt.blog/content/images/size/w600/2023/08/ares-bot.gif 600w, https://skerritt.blog/content/images/2023/08/ares-bot.gif 800w" sizes="(min-width: 720px) 720px"></figure>
<p>With many tools come many issues... Dependency issues...</p>
<p>If one of our many dependencies updated, our process was:</p>
<ol><li>Update the dependency in Rust</li><li>Build the Docker image</li><li>Push it to a registry</li><li><code>Docker pull</code> on the service</li><li><code>Docker compose up -d</code> to run it.</li></ol>
<p><strong>Every. Single. Time</strong>.</p>
<p>Here&apos;s a quick guide on how we fixed this!</p>
<h1 id="automating-the-process-away">Automating the process away</h1>
<p>The first step is updating the dependency.</p>
<p>We use <a href="https://github.com/bee-san/discord-bot/blob/aa2f56a842ce009b014e91b6631fddb939899fe4/.github/dependabot.yml?ref=skerritt.blog">Dependabot</a> to automatically detect when packages update and create pull requests for them.</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/bee-san/discord-bot/pull/28?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Bump serde from 1.0.151 to 1.0.158 by dependabot[bot] &#xB7; Pull Request #28 &#xB7; bee-san/discord-bot</div><div class="kg-bookmark-description">Bumps serde from 1.0.151 to 1.0.158. Release notes
Sourced from serde&#x2019;s releases. v1.0.158 Fix &#x201C;expected serde crate attribute to be a string&#x201D; error when using macro_rules metavariable inside of&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="How we keep our self-hosted Discord bot up to date"><span class="kg-bookmark-publisher">GitHub</span><span class="kg-bookmark-author">bee-san</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/1369264a65b4658010466596f9cca3e77e4cbaef1ff502c54e2790b644135d3e/bee-san/discord-bot/pull/28" alt="How we keep our self-hosted Discord bot up to date"></div></a></figure>
<p><strong>BUT</strong> we had to click &quot;merge&quot; every time. We wanted to automate that away too, so we built a <a href="https://github.com/bee-san/discord-bot/blob/main/.github/workflows/dependabot-automerge.yml?ref=skerritt.blog">GitHub action</a> to do this:</p>
<pre><code class="language-yaml">name: Dependabot auto-approve
on: pull_request

permissions:
  pull-requests: write

jobs:
  dependabot:
    runs-on: ubuntu-latest
    if: ${{ github.actor == &apos;dependabot[bot]&apos; }}
    steps:
      - name: Dependabot metadata
        id: metadata
        uses: dependabot/fetch-metadata@v1
        with:
          github-token: &quot;${{ secrets.PERSONAL_TOKEN }}&quot;
      - name: Approve a PR
        run: gh pr review --approve &quot;$PR_URL&quot;
        env:
          PR_URL: ${{github.event.pull_request.html_url}}
          GITHUB_TOKEN: ${{secrets.PERSONAL_TOKEN}}</code></pre>
<p>This auto-approves and merges all Dependabot pull requests.</p>
<p>Second, we want to automatically build and publish the Docker image. </p>
<p>Again, we used <a href="https://github.com/bee-san/discord-bot/blob/main/.github/workflows/docker-release.yml?ref=skerritt.blog">GitHub actions</a> here:</p>
<pre><code class="language-yaml">name: Publish Docker image

on:
  push:
    branches:
      - &apos;main&apos;

jobs:
  push_to_registry:
    name: Push Docker image to Docker Hub
    runs-on: ubuntu-latest
    steps:
      - name: Check out the repo
        uses: actions/checkout@v3
      
      - name: Log in to Docker Hub
        uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      
      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
        with:
          images: my-docker-hub-namespace/my-docker-hub-repository
      
      - name: Build and push Docker image
        uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: autumnskerritt/discord-bot:latest</code></pre>
<p>Now we have the latest image pushed to Docker everytime a commit is merged to <code>main</code> branch!</p>
<p>Now we need to update and redeploy the image on our server.</p>
<p>I created a script which pulls the image down and runs Docker Rollout on it:</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/Wowu/docker-rollout?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - Wowu/docker-rollout: &#x1F680; Zero Downtime Deployment for Docker Compose</div><div class="kg-bookmark-description">&#x1F680; Zero Downtime Deployment for Docker Compose. Contribute to Wowu/docker-rollout development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="How we keep our self-hosted Discord bot up to date"><span class="kg-bookmark-publisher">GitHub</span><span class="kg-bookmark-author">Wowu</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/0b44295cb0b55d4e017d1f7a31a13bd8a461f439ac3862bae197fb1e5df4ce0c/Wowu/docker-rollout" alt="How we keep our self-hosted Discord bot up to date"></div></a></figure>
<pre><code class="language-shell">cd ~/discord-bot
docker pull autumnskerritt/ultimate-hacking-bot:latest
docker rollout -f docker-compose.yml discord_bot</code></pre>
<p>I turned this into a service:</p>
<pre><code class="language-service">[Unit]
Description=Discord Bot Updater
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=on-failure
RestartSec=1
User=autumn
ExecStart=/usr/bin/env sh /home/autumn/discord-bot/daily_script.sh

[Install]
WantedBy=multi-user.target</code></pre>
<p>Which runs at 4am every day:</p>
<pre><code class="language-service">[Unit]
Description=Ensures the execution of the Discord bot updater every day at 4:00 AM

[Timer]
OnCalendar=*-*-* 4:00:00
Unit=discord_bot_updater.service

[Install]
WantedBy=basic.target</code></pre>
<p>&#x1F973; And now our bot is automatically up to date with the latest and greatest hacking tools.</p>
<p>Hope you enjoyed this and can use parts of it in your own automated adventures :) </p>
<p>Fancy using the bot yourself? Come try it at:</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="http://discord.skerritt.blog/?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Join the beesec Discord Server!</div><div class="kg-bookmark-description">Programming &amp; Cyber Security server | 1311 members</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="http://discord.skerritt.blog/assets/ec2c34cadd4b5f4594415127380a85e6.ico" alt="How we keep our self-hosted Discord bot up to date"><span class="kg-bookmark-publisher">Discord</span></div></div></a></figure>
<p></p>]]></content:encoded></item><item><title><![CDATA[Run your own ChatGPT in 5 minutes of work with Kobold AI]]></title><description><![CDATA[<p>This is a very quick guide on running your own ChatGPT locally. </p>
<h1 id="why-would-you-want-to-do-this">Why would you want to do this?</h1>
<ul><li><strong>You can use uncensored models</strong></li></ul>
<p>ChatGPT and the likes have an <em>alignment</em> that censors them. </p>
<p>For example, it&apos;s primarily aligned with Americans which means it&apos;s not very</p>]]></description><link>https://skerritt.blog/run-your-own-llm/</link><guid isPermaLink="false">64a925c3803e2a0001bccc0b</guid><category><![CDATA[AI]]></category><category><![CDATA[self-hosted]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Sat, 22 Jul 2023 12:47:37 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1682687220015-186f63b8850a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wxfDF8YWxsfDF8fHx8fHwyfHwxNjg4ODA2ODg1fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1682687220015-186f63b8850a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wxfDF8YWxsfDF8fHx8fHwyfHwxNjg4ODA2ODg1fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI"><p>This is a very quick guide on running your own ChatGPT locally. </p>
<h1 id="why-would-you-want-to-do-this">Why would you want to do this?</h1>
<ul><li><strong>You can use uncensored models</strong></li></ul>
<p>ChatGPT and the likes have an <em>alignment</em> that censors them. </p>
<p>For example, it&apos;s primarily aligned with Americans which means it&apos;s not very useful for most of the world.</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-10.03.34.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="1540" height="440" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-10.03.34.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-10.03.34.png 1000w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-10.03.34.png 1540w" sizes="(min-width: 720px) 720px"><figcaption><span>I did not specify which countries president...</span></figcaption></figure>
<p>It also has ethics / a moral code which prevents it from answering some questions. </p>
<p>As a security researcher, I often have to ask things which may be used for bad, like:</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-10.05.23.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="1518" height="864" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-10.05.23.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-10.05.23.png 1000w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-10.05.23.png 1518w" sizes="(min-width: 720px) 720px"></figure>
<p>There are models out there we can use which are uncensored, the developers have attempted to remove this alignment and bias from their models.</p>
<p>This is a great blog post:</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://erichartford.com/uncensored-models?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Uncensored Models</div><div class="kg-bookmark-description">I am publishing this because many people are asking me how I did it, so I will explain.
https://huggingface.co/ehartford/WizardLM-30B-Uncensored
https://huggingface.co/ehartford/WizardLM-13B-Uncensored
https://huggingface.co/ehartford/WizardLM-7B-Unc&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://cdn.hashnode.com/res/hashnode/image/upload/v1611242155728/W3_BYVVVh.png" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI"><span class="kg-bookmark-author">Eric Hartford</span><span class="kg-bookmark-publisher">Eric&apos;s Code</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://hashnode.com/utility/r?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1684106916112%2F79224ba1-66e8-4bca-abbb-168bdca0c2f1.png%3Fw%3D1200%26h%3D630%26fit%3Dcrop%26crop%3Dentropy%26auto%3Dcompress%2Cformat%26format%3Dwebp%26fm%3Dpng" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI"></div></a></figure>
<ul><li><strong>You do not have to trust OpenAI with your data</strong></li></ul>
<p>A local model means your data stays... local.</p>
<p>You do not have to upload private data to ChatGPT and risk them training a newer model on your data.</p>
<p>You do not have to trust them with customer information or whatnot when the data never, ever leaves your device.</p>
<ul><li><strong>Always available</strong></li></ul>
<p>Unlike ChatGPT which has had issues staying online, a local model is always available s0 long as your computer is online.</p>
<h1 id="%F0%9F%8D%BE-installing-a-model-locally">&#x1F37E; Installing a model locally</h1>
<p>We&apos;ll be using Kobold for this blog post.</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/LostRuins/koboldcpp?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - LostRuins/koboldcpp: A simple one-file way to run various GGML models with KoboldAI&#x2019;s UI</div><div class="kg-bookmark-description">A simple one-file way to run various GGML models with KoboldAI&#x2019;s UI - GitHub - LostRuins/koboldcpp: A simple one-file way to run various GGML models with KoboldAI&#x2019;s UI</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI"><span class="kg-bookmark-author">LostRuins</span><span class="kg-bookmark-publisher">GitHub</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/b0c1ea05323ced4e5ecc6317154a9e24a46f76b58259a38670a35f755a298607/LostRuins/koboldcpp" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI"></div></a></figure>
<p>Kobold is a small application to run local models using a fancy UI.</p>
<figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674998996172/ad4422ad-1119-4c48-b8da-fcdfdf47eba8.png?auto=compress,format&amp;format=webp" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy"></figure>
<p>We&apos;ll be running the LostRuins version because it&apos;s more up-to-date:</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-13.42.59.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="1122" height="116" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-13.42.59.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-13.42.59.png 1000w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-13.42.59.png 1122w" sizes="(min-width: 720px) 720px"><figcaption><span>It&apos;s... a lot more up to date.</span></figcaption></figure>
<h2 id="%F0%9F%94%A8-installing"> &#x1F528; Installing</h2>
<div class="kg-card kg-toggle-card" data-kg-toggle-state="close">
            <div class="kg-toggle-heading">
                <h4 class="kg-toggle-heading-text"><span>Windows users? Expand me!</span></h4>
                <button class="kg-toggle-card-icon">
                    <svg id="Regular" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                        <path class="cls-1" d="M23.25,7.311,12.53,18.03a.749.749,0,0,1-1.06,0L.75,7.311"/>
                    </svg>
                </button>
            </div>
            <div class="kg-toggle-content"><p><span>Go to releases and download an .exe file</span><br><a href="https://github.com/LostRuins/koboldcpp/releases?ref=skerritt.blog"><span>https://github.com/LostRuins/koboldcpp/releases</span><br></a></p><p><span>Then double click it and ya done!</span><br></p></div>
        </div>
<p>For Mac OS / Linux we need to:</p>
<pre><code>$ git clone git@github.com:LostRuins/koboldcpp.git
$ cd koboldcpp
$ make</code></pre>
<h2 id="%F0%9F%91%BE-choosing-a-model">&#x1F47E; Choosing a model</h2>
<p>We need to download a model. These end in <code>.bin</code> usually (for binary).</p>
<p>For people with low RAM (you need at least 7gb to run this) we can use <a href="https://huggingface.co/localmodels/WizardLM-7B-Uncensored-4bit/resolve/main/ggml/wizardlm-7b-uncensored-ggml-q4_1.bin?ref=skerritt.blog">wizardlm-7b-uncensored</a>.</p>
<p>You can choose any model you want, and if you have more RAM or a better GPU you might want to choose another model.</p>
<p>The subreddit LocalLLaMA regularly updates its wiki with the latest and greatest models:</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.reddit.com/r/LocalLLaMA/wiki/models/?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">models - LocalLLaMA</div><div class="kg-bookmark-description">r/LocalLLaMA: Subreddit to discuss about Llama, the large language model created by Meta AI.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.redditstatic.com/desktop2x/img/favicon/android-icon-192x192.png" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI"><span class="kg-bookmark-publisher">reddit</span></div></div></a></figure>
<p>Once you find a model you like, download the <code>.bin</code> onto your computer.</p>
<p>I have made a folder <code>/models</code> which I store all my models in.</p>
<pre><code>$ cd /models
$ wget https://huggingface.co/localmodels/WizardLM-7B-Uncensored-4bit/resolve/main/ggml/wizardlm-7b-uncensored-ggml-q4_1.bin</code></pre>
<p>Now we run the Python file followed by the LLM and a port:</p>
<pre><code>$ python3 koboldcpp.py /home/autumn/models/wizardlm-7b-uncensored-ggml-q4_1.bin.1 9057</code></pre>
<p>Now go to <code>localhost:9057</code> if you&apos;re running it locally and you should see...</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.44.30-1.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="2000" height="1188" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-15.44.30-1.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-15.44.30-1.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/07/Screenshot-2023-07-08-at-15.44.30-1.png 1600w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.44.30-1.png 2380w" sizes="(min-width: 720px) 720px"><figcaption><span>&#x1F973;</span></figcaption></figure>
<p>We&apos;ll ask it a quick question to check it works.</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.46.47.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="2000" height="453" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-15.46.47.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-15.46.47.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/07/Screenshot-2023-07-08-at-15.46.47.png 1600w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.46.47.png 2358w" sizes="(min-width: 720px) 720px"></figure>
<p>Ok, that&apos;s not the current monarch of the UK but maybe the data doesn&apos;t go back that far &#x1F937;&#x200D;&#x2640;&#xFE0F;</p>
<p>If we check our terminal we can see it took around 20 seconds to run!</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.47.56.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="1414" height="368" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-15.47.56.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-15.47.56.png 1000w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.47.56.png 1414w" sizes="(min-width: 720px) 720px"></figure>
<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F389;</div><div class="kg-callout-text"><b><strong>AND WE&apos;RE DONE!</strong></b> In just 5 minutes of work (and maybe 10 minutes of downloading) we now have our own ChatGPT entirely locally, and we can use any model we like.</div></div>
<h1 id="%F0%9F%91%AE-censorship-test">&#x1F46E; Censorship test</h1>
<p>Remember earlier when I tried to ask ChatGPT questionable things? Let&apos;s try it on WizardLM uncensored.</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.51.45.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="2000" height="128" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-15.51.45.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-15.51.45.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/07/Screenshot-2023-07-08-at-15.51.45.png 1600w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.51.45.png 2318w" sizes="(min-width: 720px) 720px"></figure>
<p>Ok, still American-centric.</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.52.58.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="1684" height="228" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-15.52.58.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-15.52.58.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/07/Screenshot-2023-07-08-at-15.52.58.png 1600w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.52.58.png 1684w" sizes="(min-width: 720px) 720px"></figure>
<p>Ay! This is exactly how I would exploit Eternal Blue.</p>
<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F42C;</div><div class="kg-callout-text">Metasploit is nice but I prefer auto blue for rooting boxes now-a-days <a href="https://github.com/3ndG4me/AutoBlue-MS17-010?ref=skerritt.blog">https://github.com/3ndG4me/AutoBlue-MS17-010</a></div></div>
<h1 id="%F0%9F%93%9A-scenarios">&#x1F4DA; Scenarios</h1>
<p>WizardLM features a neat <code>scenarios</code> tab.</p>
<p>ChatGPT is one specific scenario where you ask someone a question and get a reply. Most LLMs do not work like this off the bat, they need some sort of training or scenario to work in such a way.</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.59.30.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="1192" height="1204" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-15.59.30.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-15.59.30.png 1000w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.59.30.png 1192w" sizes="(min-width: 720px) 720px"></figure>
<p>For instance you can immerse yourself into your favourite Isekai or create your own ChatGPT.</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.59.50.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="1186" height="254" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-15.59.50.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-15.59.50.png 1000w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-15.59.50.png 1186w" sizes="(min-width: 720px) 720px"></figure>
<p>Or you can talk to Special Agent Katia.</p>
<figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-16.00.19.png" class="kg-image" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI" loading="lazy" width="1182" height="250" srcset="https://skerritt.blog/content/images/size/w600/2023/07/Screenshot-2023-07-08-at-16.00.19.png 600w, https://skerritt.blog/content/images/size/w1000/2023/07/Screenshot-2023-07-08-at-16.00.19.png 1000w, https://skerritt.blog/content/images/2023/07/Screenshot-2023-07-08-at-16.00.19.png 1182w" sizes="(min-width: 720px) 720px"></figure>
<p>You can use any scenario on Aetherroom too:</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://aetherroom.club/?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">/aids/ Prompts</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://aetherroom.club/apple-touch-icon.png" alt="Run your own ChatGPT in 5 minutes of work with Kobold AI"><span class="kg-bookmark-publisher">/aids/ Prompts</span></div></div></a></figure>
<h1 id="conclusion"> Conclusion</h1>
<p>That&apos;s... it!</p>
<p>It&apos;s super easy to run your own version of ChatGPT so long as you have the specs for it.</p>]]></content:encoded></item><item><title><![CDATA[SSH Permission denied (publickey).]]></title><description><![CDATA[<h1 id="solution-1regenerate-the-key">Solution 1 - Regenerate the key</h1>
<ol><li>Generate your key.</li><li>Configure ssh to use the key.Your config file should have something similar to the following:You can add <code>IdentitiesOnly yes</code> to ensure <code>ssh</code> uses the specified <code>IdentityFile</code> and no other keyfiles during authentication. </li></ol>
<p>Setting <code>IdentitiesOnly</code> prevents failed authentications from occurring,</p>]]></description><link>https://skerritt.blog/ssh-permission-denied-publickey/</link><guid isPermaLink="false">6499309792b1040001996985</guid><category><![CDATA[ssh]]></category><category><![CDATA[debug]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Thu, 29 Jun 2023 10:51:18 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1682685797703-2bb22dbb885b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wxfDF8YWxsfDF8fHx8fHwyfHwxNjg4MDM0NjQ4fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<h1 id="solution-1regenerate-the-key">Solution 1 - Regenerate the key</h1>
<ol><li>Generate your key.</li><li>Configure ssh to use the key.Your config file should have something similar to the following:You can add <code>IdentitiesOnly yes</code> to ensure <code>ssh</code> uses the specified <code>IdentityFile</code> and no other keyfiles during authentication. </li></ol>
<img src="https://images.unsplash.com/photo-1682685797703-2bb22dbb885b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wxfDF8YWxsfDF8fHx8fHwyfHwxNjg4MDM0NjQ4fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="SSH Permission denied (publickey)."><p>Setting <code>IdentitiesOnly</code> prevents failed authentications from occurring, when <code>ssh</code> would otherwise attempt to login with multiple keys. </p>
<p>Setting this is also considered more secure, as you&apos;re not leaking information about other keys you have installed, and maintaining separation of your keys between different levels of access.</p>
<ol><li>Copy your key to your server.</li></ol>
<h1 id="solution-2perms">Solution 2 - Perms</h1>
<p>Sometimes the issue comes from permissions and ownership. For instance, if you want to log in as root, <code>/root</code>, <code>.ssh</code> and <code>authorized_keys</code> must belong to root. Otherwise, sshd won&apos;t be able to read them and therefore won&apos;t be able to tell if the user is authorized to log in.</p>
<p>In your home directory:</p>
<pre><code class="language-sh">chown -R your_user:your_user .ssh
</code></pre>
<p>As for rights, go with 700 for <code>.ssh</code> and 600 for <code>authorized_keys</code></p>
<pre><code class="language-sh">chmod 700 .ssh
chmod 600 .ssh/authorized_keys</code></pre>
<h1 id="solution-3sshing-into-the-home-directory">Solution 3 - SSHing into the home directory</h1>
<p>Also make sure that the user&apos;s home directory (on the server) actually belongs to the user ssh&apos;ing into (was set to root:root in my case).</p>
<p>Should have been:</p>
<pre><code>sudo chown username:username /home/username;</code></pre>
<h1 id="solution-4if-you-have-access-to-both-machines">Solution 4 - if you have access to both machines</h1>
<p>The following method might work if you can access machineA and machineB independently (e.g. from machineC).</p>
<p>If ssh-copy-id is not working, password authentication could be disabled. <strong>The following is a workaround</strong>.</p>
<p>Having machineA&apos;s public key in machineB&apos;s authorized keys (i.e. ~/.ssh/authorized_keys) will allow you to ssh from machineA. This also applies to scp.</p>
<p>After generating the key pairs using: <code>ssh-keygen</code></p>
<p>On <strong>machineA</strong>, execute <code>cat ~/.ssh/id_rsa.pub</code></p>
<p>Sample output:</p>
<blockquote><code>ssh-rsa AAAAB3NzaSGMFZW7yB anask@mahineA</code></blockquote>
<p>Copy the printed key (&#x2318; Command+C, or CRTL+C) then add it to the ~/.ssh/authorized_keys file on <strong>machineB</strong>.</p>
<p>For example, execute the following on <strong>machineB</strong>:</p>
<blockquote><code>echo &apos;ssh-rsa AAAAB3NzaSGMFZW7yB anask@mahineA&apos;  &gt;&gt; ~/.ssh/authorized_keys</code></blockquote>
<h1 id="tailscale-ssh-permission-denied">Tailscale SSH Permission denied</h1>
<p>In my case, my Tailscale key had expired. I needed to go into the Tailscale UI and stop it from expiring or create another key.</p>]]></content:encoded></item><item><title><![CDATA[Packaging your Python Project]]></title><description><![CDATA[<p>I was looking to package my project, Ciphey, for operating systems and for managers that aren&#x2019;t PyPi. Unfortunately, there seemed to be very little information on the web about this.</p><p>This is a guide on packaging your Python project for:</p><ul><li>PyPi</li><li>HomeBrew</li><li>Windows Package Manager</li><li>Arch User Repository</li></ul>]]></description><link>https://skerritt.blog/packaging-your-python-project/</link><guid isPermaLink="false">62dbf9771e7152003d2c39db</guid><category><![CDATA[python]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Sun, 25 Jun 2023 07:35:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1687599556215-536da19dc9ca?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8YWxsfDJ8fHx8fHwyfHwxNjg3NjgwMjcyfA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1687599556215-536da19dc9ca?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8YWxsfDJ8fHx8fHwyfHwxNjg3NjgwMjcyfA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Packaging your Python Project"><p>I was looking to package my project, Ciphey, for operating systems and for managers that aren&#x2019;t PyPi. Unfortunately, there seemed to be very little information on the web about this.</p><p>This is a guide on packaging your Python project for:</p><ul><li>PyPi</li><li>HomeBrew</li><li>Windows Package Manager</li><li>Arch User Repository</li></ul><h1 id="semantic-versioning">Semantic Versioning</h1><p>Semantic Versioning is a system defining how to write version numbers. The 3 numbers are:</p><pre><code>Major.Minor.Bugs
</code></pre><p>If you have fixed some bugs, increment the bugs counter.</p><p>If you have added a minor feature, increment the minor counter.</p><p>If you have done something major, increment the major counter.</p><p>We can signify whether a release is still being rested or not by adding &#x201C;rc&#x201D; (release candidate) to the end of the version. &#x201C;5.0.0rc1&#x201D; signifies &#x201C;release candidate 1&#x201D; which means this is the first public testing release of version 5.0.0.</p><h1 id="pypi">PyPi</h1><p>The traditional method of using Setuptools is outdated and old. There&#x2019;s a new cowboy in town, and their name is Poetry.</p><p>Poetry creates a <code>pyproject.yml</code> file, which is the <a href="https://www.python.org/dev/peps/pep-0517/?ref=skerritt.blog">successor</a> to the 3-file Setuptools system.</p><p>You should use Poetry because:</p><ul><li>Instead of 3 files, it is now 1 file</li><li>That 1 file is yaml, which means you don&#x2019;t have to cry reading weirdly formatted Python code used as a replacement for yaml</li><li>You can separate dev &amp; normal dependencies, so users only install the dependencies they need to run the app</li><li>It&#x2019;s physically easier to build and upload to PyPi</li><li>And a host of other things</li></ul><p>Install poetry with <code>pip3 install poetry</code>.</p><p>Navigate to your projects directory and run the command <code>poetry init</code>.</p><p>This will generate a <code>pyproject.toml</code> file. This file contains everything PyPi needs to upload your project and allow other users to download it.</p><p>Let&#x2019;s run through the sections in this new file, and fill them out as we go.</p><p><strong>[tool.poetry]</strong></p><p>This section relates to the metadata of your project.</p><p>The name, description, version etc.</p><p>To add a new variable to a .toml file, write it as if it were python <code>name = &quot;project name&quot;</code>.</p><p>The most important ones we&#x2019;ll want are:</p><ul><li>Name</li></ul><p>What is the name of the project?</p><pre><code>name = &quot;Ciphey`
</code></pre><ul><li>Version</li></ul><p>The semantic version number.</p><pre><code>version = &quot;5.0.0rc6&quot;
</code></pre><ul><li>Description</li></ul><p>Short one-line description.</p><pre><code>description = &quot;Automated decryption tool&quot;
</code></pre><ul><li>Authors</li></ul><p>A list containing the author&apos;s name and email address. In the format of <code>authors = [&quot;brandon &lt;brandon@fake.com&gt;&quot;]</code></p><ul><li>License</li></ul><p>What license does the project use?</p><pre><code>license = &quot;MIT&quot;
</code></pre><ul><li>readme</li></ul><p>The name of the <code>README.md</code> file, in the same directory, as <code>pyproject.toml</code>.</p><pre><code>readme = &quot;README.md&quot;
</code></pre><p>Here is what Ciphey&#x2019;s Pyproject looks like:</p><pre><code>[tool.poetry]
name = &quot;ciphey&quot;
version = &quot;5.0.0rc4&quot;
description = &quot;Automated Decryption Tool&quot;
authors = [&quot;Brandon &lt;brandon@skerritt (dot) blog&gt;&quot;]
license = &quot;MIT&quot;
documentation = &quot;https://docs.ciphey.online&quot;
exclude = [&quot;tests/hansard.txt&quot;]
readme = &quot;README.md&quot;
</code></pre><p>To find out what else you can include, check out the <a href="https://python-poetry.org/docs/pyproject/?ref=skerritt.blog">Poetry documentation.</a></p><p><strong>[tool.poetry.dependencies]</strong></p><p>A list of all the dependencies your project uses. Don&#x2019;t worry! You don&#x2019;t have to manually add them to the list.</p><p>Run the command <code>poetry add &lt;dependency&gt;</code> to add a dependency to your project, and Poetry will automatically add it to your project.</p><p>For example, to add <code>rich</code> we would write <code>poetry add rich</code>.</p><p><strong>[tool.poetry.dev-dependencies]</strong></p><p>The dependencies the developers of your tool rely on. To add the testing library Pytest, write <code>poetry add --dev pytest</code>.</p><p><strong>[tool.poetry.scripts]</strong></p><p>This is the 2nd most important part! As it contains an entry point. When a user installs your package, you&#x2019;d probably like them to be able to run <code>package</code> in their terminal and use your package.</p><p>For a folder called Ciphey with a file named Ciphey.py with a function called main(), we would write:</p><pre><code>ciphey = &apos;ciphey.ciphey:main&apos;
</code></pre><p>When the user runs the command <code>ciphey</code>, it actually runs the main function of the file ciphey of the folder ciphey.</p><p>For a more detailed explanation, <a href="https://amir.rachum.com/blog/2017/07/28/python-entry-points/?ref=skerritt.blog">check this out.</a></p><h2 id="poetry-run">Poetry Run</h2><p><code>poetry run</code> runs our script but includes the <code>pyproject.toml</code> file. It executes the given command inside of a virtual environment, essentially it allows us to test our project in the same way a user might run our program.</p><h2 id="poetry-install">Poetry Install</h2><p><code>Poetry install</code> installs our program and all its dependencies. Essentially, we can test exactly what our users will do when they install the project for themselves.</p><h2 id="poetry-update">Poetry Update</h2><p><code>poetry update</code> updates our dependencies.</p><h2 id="poetry-build">Poetry Build</h2><p>Now onto the most important commands. <code>Poetry build</code> builds our project, which means it generates some files that other users can install and use on their system.</p><h2 id="poetry-publish">Poetry Publish</h2><p><code>Poetry Publish</code> will publish the package to PyPi for us. All we need to do is enter a username/password.</p><p>And just like that, our project is now on PyPi for the whole world to download!</p><h1 id="windows-package-manager-winget">Windows Package Manager (WinGet)</h1><p>There are 3 steps to submitting your app to WinGet.</p><ol><li>Turning your project into an EXE</li><li>Create a manifest file</li><li>Create a pull request on GitHub</li></ol><h2 id="turning-your-project-into-an-exe">Turning your project into an EXE</h2><p>Windows requires an exe file for Python projects. Don&#x2019;t fret! Turning your project into an exe file isn&#x2019;t that difficult.</p><p>Download Pyinstaller, and then create an <code>entry point</code> in the root directory.</p><p>An entry point is a Python file that when run, will run the program. So for instance:</p><pre><code>Ciphey/
|-entry_point.py
|-ciphey/
|----main.py
</code></pre><p>Here the project code is in <code>ciphey/</code>. To run the program, we&#x2019;d have to run <code>python3 ciphey/main.py</code>.</p><p>This is the typical file structure of a project. We have README.md and similar in the root, and all the source code in a sub-directory.</p><p>We must create a program that calls our program using an entry point. The entry point is a function which runs the program.</p><p>If you have a <code>setup.py</code> or <code>pyproject.yml</code>, you may already have entry points defined in them.</p><p>In <code>entry_point.py</code>, we&#x2019;d write:</p><pre><code>from ciphey.__main__ import main

if __name__ == &apos;__main__&apos;:
    main()
</code></pre><p>Or however, your entry point is defined.</p><p>Now, run Pyinstaller on the <code>entry_point.py</code> file. It will generate a new folder called <code>dist/</code>. If you are using the default Python <code>.gitignore</code> it will automatically disclude <code>dist/</code>. If not, please add it to the <code>.gitignore</code>!</p><p>Pyinstaller will also generate a <code>entry_point.spec</code> file in the root directory. This file contains a specification of how Pyinstaller should build your program.</p><p>Once built, run the program.</p><p>You will likely see some errors. Most likely bad imports. To fix this, define them in the spec file. There are a couple main lists in the spec file you should know about:</p><ul><li>Binaries</li></ul><p>If you already hold a binary for a specific file/library (such as C++ compiled) then define the location here.</p><ul><li>Data</li></ul><p>If your program relies on .txt data or anything that isn&#x2019;t a Python file define it here.</p><ul><li>Hidden Imports</li></ul><p>Hidden imports look like <code>__import__</code>. &#xA0;These types of imports are not visible to Pyinstaller&#x2019;s analysis, so to get around this define the imports in the Hidden imports section.</p><ul><li>Excludes</li></ul><p>Exclude a package from Pyinstaller. I had an error with Setuptools, but since Setuptools isn&#x2019;t needed to run Ciphey I told Pyinstaller to exclude the entire package.</p><p>If you have edited the <code>.spec</code> file, you may want to delete the line the <code>.gitignore</code> which states to ignore the file. Otherwise, all the hard work you&#x2019;ve spent in getting Pyinstaller to work may be lost.</p><p><strong>One thing to note</strong>. Pyinstaller only creates executables for the system you are on. You cannot build a Windows .exe from Linux. You have to be on the system you are trying to build. Pyinstaller can create these binaries (assuming you own the operating systems for them):</p><ul><li>Windows .exe</li><li>Mac OS&#x2019; .app</li><li>Linux&#x2019;s Binary Files</li></ul><p>Once built and packaged, running the executable on Windows / Mac will bring up the Terminal (assuming you do not have any GUI). If you do, it will bring up the GUI.</p><p>Pyinstaller packages an entire Python interpreter with the binary, So do not worry about the user having Python installed.</p><h2 id="manifest-file">Manifest File</h2><p>Now we have an exe. I would suggest converting to MSIX.</p><p>Exes are cool and all, but they&#x2019;re not really package manager material. Winget with a .exe is a glorified Softonic / CNET Software. MSIX gives us the real power to:</p><ul><li>Automatically update the app</li><li>Uninstall cleanly</li><li>Understand what dependencies are required</li></ul><p>So in short, if we use a .exe it is just a glorified Software downloader. If we use .msix it is more of a package manager.</p><p>Below is the <code>manifest.yml</code> file for Ciphey.</p><pre><code>Id: Ciphey.Ciphey 
Publisher: Ciphey
Name: Ciphey 
Version: 5
AppMoniker: Ciphey
MinOSVersion: 10.0.0.0
Description: Automated Decryption Tool
Homepage: https://www.github.com/ciphey/ciphey
License: MIT
LicenseUrl: https://opensource.org/licenses/MIT 
InstallerType: exe
Installers:
  - Arch: x64
    Url: https://statics.teams.cdn.office.net/production-windows-x64/1.3.00.4461/Teams_windows_x64.exe
    Sha256: 712f139d71e56bfb306e4a7b739b0e1109abb662dfa164192a5cfd6adb24a4e1
ManifestVersion: 0.1.0
</code></pre><p>Ciphey&#x2019;s manifest file Let&#x2019;s walk through quickly what each potentially confusing part is. I&#x2019;ll leave things like &#x201C;Name&#x201D; and &#x201C;License&#x201D; as they are self-explanatory.</p><ul><li>ID</li></ul><p>This follows a <code>publisher.package</code> format. Your publisher&apos;s name, and then the package name.</p><ul><li>App Moniker</li></ul><p>What&#x2019;s the common name people search for your package with? For example &#x201C;Visual Studio Code&#x201D; can also be found with &#x201C;vscode&#x201D;.</p><p>If you have a long package name and your users often shorten it, this will be helpful to you.</p><ul><li>MinOSVersion</li></ul><p>What is the minimum version of Windows the app supports? <code>10.0.0.0</code> means Windows 10 and above.</p><ul><li>InstallerType</li></ul><p>What type of installer do you have? If you followed along, you should have a .exe file.</p><ul><li>Installers</li></ul><p>This details how to install your package.</p><ol><li>Architecture</li></ol><p>What architecture does your project support? Examples include <code>arm, arm64, x86, x64 and neutral</code>.</p><p>The ones you&#x2019;re probably after are either x86 or x64. x86 is for 32-bit operating systems, x64 is for 64-bit operating systems.</p><ol><li>URL</li></ol><p>What is the URL of the .exe installer for your project? Personally, I hosted this on GitHub.</p><ol><li>SHA256</li></ol><p>What is the SHA256 checksum of your .exe file? There&#x2019;s an article <a href="https://kanguru.zendesk.com/hc/en-us/articles/235228027-SHA256-Checksum-Utilities?ref=skerritt.blog">here</a> detailing how to calculate it.</p><ul><li>Manifest Version</li></ul><p>Every time you update this file, update the manifest version numbering using Semantic Versioning.</p>]]></content:encoded></item><item><title><![CDATA[Set Theory for Programmers]]></title><description><![CDATA[<p>If you&#x2019;ve spent time on <a href="https://www.hackerrank.com/?ref=skerritt.blog">HackerRank</a> or <a href="https://leetcode.com/?ref=skerritt.blog">LeetCode</a>, you might have noticed most of the optimal solutions use Set Theory. By reading this article, you will gain a deeper knowledge into set theory and how to use it to create optimal algorithms.</p><p>Set Theory was invented (or found,</p>]]></description><link>https://skerritt.blog/sets/</link><guid isPermaLink="false">637ce3fc8e6225003d41d88f</guid><category><![CDATA[Algorithms]]></category><category><![CDATA[programming]]></category><category><![CDATA[Popular]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Sat, 24 Jun 2023 12:38:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1673264809315-9d7c34f0a22d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDI5fHx8fHx8Mnx8MTY3MzM2NjgyNg&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1673264809315-9d7c34f0a22d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDI5fHx8fHx8Mnx8MTY3MzM2NjgyNg&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Set Theory for Programmers"><p>If you&#x2019;ve spent time on <a href="https://www.hackerrank.com/?ref=skerritt.blog">HackerRank</a> or <a href="https://leetcode.com/?ref=skerritt.blog">LeetCode</a>, you might have noticed most of the optimal solutions use Set Theory. By reading this article, you will gain a deeper knowledge into set theory and how to use it to create optimal algorithms.</p><p>Set Theory was invented (or found, depending on how you view maths) by <a href="https://en.wikipedia.org/wiki/Georg_Cantor?ref=skerritt.blog">George Cantor.</a></p><p>It revolves around the idea of sets, as in collections of objects. Set theory is incredibly powerful and can be used to write some beautiful &amp; elegant code.</p><h2 id="%F0%9F%A4%94-what-is-a-set">&#x1F914; What is a Set?</h2><p>A set is simply a set of objects. They don&#x2019;t have to be the same type or have any relation to one another.</p><pre><code class="language-python">set = (apples, pears, oranges)</code></pre><p>Sets are denoted with parenthesis <code>( )</code>. With the separation of elements being a comma. Or sometimes <code>{ }</code>. Sets follow 2 rules:</p><ul><li>Only unique items.</li></ul><p>Sets can only contain unique items. It cannot contain the same item twice or more.</p><ul><li>The set is unordered.</li></ul><p>There is no order or structure to a set. The first rule is quite useful. Say, for example, we have a list of words from a book:</p><pre><code class="language-python">words = [&quot;hello&quot;, &quot;my&quot;,  &quot;name&quot;, &quot;is&quot;, &quot;brandon&quot;, &quot;and&quot;,
&quot;your&quot;, &quot;name&quot;, &quot;is&quot;, &quot;brandon&quot;]</code></pre><p>To find all the unique words, we put the words into a set:</p><pre><code class="language-python">words = [&quot;hello&quot;, &quot;my&quot;,  &quot;name&quot;, &quot;is&quot;, &quot;brandon&quot;, &quot;and&quot;,
&quot;your&quot;, &quot;name&quot;, &quot;is&quot;, &quot;brandon&quot;]

unique = set(words)
# {&apos;hello&apos;, &apos;is&apos;, &apos;and&apos;, &apos;brandon&apos;, &apos;my&apos;, &apos;your&apos;, &apos;name&apos;}</code></pre><p>The 2nd rule ties in nicely with the 1st rule. <strong>A set aims to replicate how we see things in our lives.</strong></p><p>Imagine we are on a road trip with Jahan, Olivia, and Ryan.</p><p>Next year, we want to go on a field trip again. It doesn&#x2019;t make much sense to invite Jahan, Olivia, Jahan, Ryan, and Jahan.</p><p>And it also doesn&#x2019;t make sense to assign an &#x201C;order&#x201D; to them. They&#x2019;re people, not elements in an array! There are other types of sets too. Such as a <a href="https://en.wikipedia.org/wiki/Multiset?ref=skerritt.blog">multiset</a> which allows non-unique elements but no order.</p><h2 id="%F0%9F%A6%81-cardinality">&#x1F981; Cardinality</h2><p>The cardinality of a set is the length of the set. For the set:</p><p>$$A = \{1, 2, 3, 4, 5, 6\}$$</p><p>The cardinality is:</p><p>$$|A| = 6$$</p><h2 id="%F0%9F%9A%B4%E2%80%8D%E2%99%80%EF%B8%8F-equality-of-sets">&#x1F6B4;&#x200D;&#x2640;&#xFE0F; Equality of Sets</h2><p>2 sets are equal when all the elements match.</p><p>$$a = \{1, 2, 3\}$$</p><p>$$b = \{3, 2, 1\}$$</p><p>$$a == b$$</p><p><strong>Remember, the order doesn&#x2019;t matter</strong> - so sets are equal despite being in the &#x2018;wrong&#x2019; order!</p><h2 id="%F0%9F%9A%87-infinite-sets">&#x1F687; Infinite Sets</h2><p>Some sets are infinite. Such as the set containing all the natural numbers, or all the real numbers.</p><p>We can express infinite sets using a little bit of maths. Heard of <a href="https://skerritt.blog/learn-functional-python-in-10-minutes/">list comprehensions</a>? It looks the same syntactically but operates infinitely.</p><p>The set of all even numbers is:</p><p>$$A = \{2n: n \in \mathbb{Z}\}$$</p><p>Read this as &quot;For each number, n, in the set of all integers, Z, multiply the number by 2&quot;. Which will give us the set of all even numbers.</p><p>Which will give us the set of all even numbers.</p><p>In a list comprehension, it would look like this:</p><pre><code class="language-python">[2 * n for n in naturalNumbers] </code></pre><p>However, this won&#x2019;t work as Python doesn&#x2019;t allow infinite sets.</p><h2 id="%F0%9F%90%88%E2%80%8D%E2%AC%9B-the-empty-set">&#x1F408;&#x200D;&#x2B1B; The Empty Set</h2><p>The empty set is the set containing nothing at all. It is much like 0. It is nothing and serves the purpose of a negated value. We don&#x2019;t have 0 apples, we have no apples.</p><p>The empty set serves the same purpose. We don&#x2019;t have a set containing all the words, we have nothing.</p><p>Its symbol is &#x2205;</p><h2 id="%F0%9F%8C%8C-the-universal-set">&#x1F30C; The Universal Set</h2><p>The Universal Set, U, &#xA0;is the set which contains all objects, including itself. If our universe contains only integers, 1, 2, 3, &#x2026;, then the universal set is the set of all integers.</p><h2 id="%F0%9F%8F%A5-operations">&#x1F3E5; Operations</h2><p>Just like with other data types, sets have operations! Let&#x2019;s start with some operations you may already know.</p><h2 id="%E2%9D%8C-union">&#x274C; Union</h2><p>The union is combining 2 sets together (think addition). The symbol for the union is &#x222A;. Let&#x2019;s look at an example.</p><p>$$A = \{1, 2, 3\}$$</p><p>$$B = \{3, 4, 5\}$$</p><p>$$B \cup A = \{1, 2, 3, 4, 5\}$$</p><p>Notice how when we perform a union, we have two threes. Since sets only contain unique elements, we simply toss the extra 3 away. Also note, there is no order. So B &#x222A; A does not result in (3, 4, 5&#x2026;) as the order doesn&#x2019;t exist.</p><p>We can even say B &#x222A; A = {3, 5, 1, 4, 2}. What if we union an empty set with a non-empty set? Or an empty set with another empty set?</p><p>$$\varnothing \cup {1, 2, 3} = {1, 2, 3}$$</p><p>$$\varnothing \cup \varnothing = \varnothing$$</p><p>When we get onto subsets and the like we&#x2019;ll learn to appreciate the empty set and this simplistic maths.</p><h2 id="%F0%9F%A6%84-intersection">&#x1F984; Intersection</h2><p>The intersection of a set is every item in set A that is also in set B.</p><p>Think of it like the boolean operator AND. Its symbol is &#x2229;.</p><p>$$A = \{1, 2, 3\}$$</p><p>$$B = \{3, 4, 5\}$$</p><p>$$A \cap B = \{3\}$$</p><p>Let&#x2019;s say we have a list of flights with passengers on board. And we have a list of the people that took my daughter (<a href="https://en.wikipedia.org/wiki/Taken_(film)?ref=skerritt.blog">Taken</a> reference).</p><p>We can use the intersection operation to find the list of flights that contain the people who took my daughter.</p><p>Because sets only contain unique elements, it is very fast to calculate this. However, creating the set itself may take time. But, if we do not know all the names of the people in the child trafficking ring we can build the set first and use the intersection to query it.</p><h2 id="%F0%9F%92%8D-belongs-to">&#x1F48D; Belongs To</h2><p>We can create sets which belong to other sets.11 belongs to set 1,2,31,2,3. In notation, this is:</p><p>$$1 \in {1, 2, 3}$$</p><p>We say that &#x201C;1 is in the set {1, 2, 3}&quot;.</p><p>But don&#x2019;t get caught out!</p><p>$$\{1\} \in \{1, 2, 3\}$$</p><p>That is not true. We say the element is not in &#x2209; the set.</p><p>$$\{1\} \notin \{1, 2, 3\}$$</p><p>It would be true if:<br><br>$$\{1\} \in \{\{1\}, 2, 3\}$$</p><p>This is a very, very useful feature. Let&#x2019;s say we have the word &#x201C;FLAG{&#x201D; that we want to find in some text. We turn the text into a set, like so:</p><pre><code class="language-python">text = &quot;FLAG{&quot;
corpus = set(&quot;Hello&quot;,  &quot;my&quot;, &quot;name&quot;, &quot;is&quot;)
if text in corpus:
	print(&quot;It&apos;s in there!&quot;)</code></pre><p>Because sets do not contain unique items, this is rather fast. However, you have to take into account that turning it into a set is expensive.</p><h2 id="%F0%9F%9B%A9%EF%B8%8F-subset">&#x1F6E9;&#xFE0F; Subset</h2><pre><code class="language-python">original = {1, 2, 3, 4}
subset1 = {1}
subset2 = {3, 4}
subset3 = {4, 3, 2, 1} </code></pre><p>The symbol for subset is \(\{1\} \subset \{1, 2\}\).</p><p>The empty set is a subset of all sets, but it is <strong>not an element of all sets</strong>.</p><p>Fun fact, we can do this:</p><p>$$ \mathbb{U} - &#xA0;\varnothing$$</p><p>This equates to a new set, which contains all the elements of the set apart from the empty set. However, it is not the universal set - it&#x2019;s a new set!</p><p>The power in subsets, in my opinion, comes from the <strong>power set</strong>.</p><h2 id="%F0%9F%94%8B-power-set">&#x1F50B; Power Set</h2><p>The Power set is the set of all subsets of a set, including the empty set and the set itself. For the set <code>{2, 9}</code> we have 4 subsets.</p><pre><code class="language-python">{}
{2}
{9}
{2, 9}
</code></pre><p>The power set will be:</p><p>$$\frak{P} (\mathbb{A}) = \emptyset, \{2\}, \{9\}, \{2, 9\}$$</p><p><em>Note: For home use or exams we can denote using P(a). For websites where we want to impress people with our fancy use of the alphabet, use LaTeX.</em></p><p>When building subsets, the element can either be included in the subset or not. This is binary. It&#x2019;s either in it, or it isn&#x2019;t.</p><p>That leads us to the formula for calculating how large a powerset is. </p><p>$$2^{s}$$</p><p>Where s is the size of the set and 2 is because elements are either in the set or not.</p><p>Let&#x2019;s say we have a list of ingredients.</p><pre><code>{cabbage, lettuce, tomato, chips, carrots}</code></pre><p>It makes sense to use a set because the order doesn&#x2019;t matter for a list of ingredients and we don&#x2019;t want to have cabbage twice for some reason.</p><p>Now, how many combinations of food can we make with this?</p><p>$$2^{35} = 32$$</p><p>The empty set doesn&#x2019;t count here (unless we want to starve), so we can reduce this to 31.</p><h2 id="%F0%9F%A5%BA-infographic-cheat-sheet-for-set-theory"><br>&#x1F97A; Infographic Cheat Sheet for Set Theory</h2><p>I made this for you! Feel free to print and use it however you want. Personally, when I was studying for exams, the symbols section proved to be most useful!</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-163.png" class="kg-image" alt="Set Theory for Programmers" loading="lazy" width="800" height="1491" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-163.png 600w, https://skerritt.blog/content/images/2023/06/image-163.png 800w" sizes="(min-width: 720px) 720px"></figure><h2 id="%F0%9F%92%BB-sets-in-programming-languages-are-often-sorted"><br>&#x1F4BB; Sets in Programming Languages Are Often Sorted</h2><p>Not only do sets in most programming languages are often automatically sorted. Take a look at this Python code:</p><pre><code class="language-python">&gt;&gt;&gt; x = [9, 8, 7, 6, 5, 4, 3, 2, 1]
&gt;&gt;&gt; set(x)
{1, 2, 3, 4, 5, 6, 7, 8, 9}
</code></pre><p>And that&#x2019;s just the tip of the iceberg. Sets are implemented as hash maps in many programming languages. This means that we get O(1) lookup time. To perform <code>6 in x</code> will take O(1) time. <a href="https://skerritt.blog/big-o/">For more on Big O notation, check out my other article.</a></p><h2 id="%F0%9F%93%96-dictionary-checking">&#x1F4D6; Dictionary Checking</h2><p>We have a text such as:</p><pre><code class="language-python">text = [&quot;hello&quot;, &quot;my&quot;, &quot;name&quot;, &quot;is&quot;, &quot;lkmxjja&quot;, &quot;brandon&quot;]
</code></pre><p>And we want to find out how many words in <code>text</code> appear in another list, <code>text_dict</code>.</p><pre><code class="language-python">text_dict = [&quot;hello&quot;, &quot;hello&quot;, &quot;my&quot;, &quot;brandon&quot;, &quot;name&quot;]
</code></pre><p>The quickest way to do this without using sets is to sort both lists and then go through each one, one at a time to count how many times an item in <code>text</code> appears in <code>text_dict</code>.</p><p>In a real-world example, we could be checking to see if a text is English or not by counting how many times the words in the text appear in the English dictionary.</p><p>By using sets, we delete the repetitions in <code>text_dict</code>. It also automatically sorts the two sets, so it is much easier for us to search through them. Not to mention the O(1) lookup time.</p><p>3 birds with 1 stone!</p><pre><code class="language-python">&gt;&gt;&gt; text = [&quot;hello&quot;, &quot;my&quot;, &quot;name&quot;, &quot;is&quot;, &quot;lkmxjja&quot;, &quot;brandon&quot;]
&gt;&gt;&gt; text_dict = [&quot;hello&quot;, &quot;hello&quot;, &quot;my&quot;, &quot;brandon&quot;, &quot;name&quot;]
&gt;&gt;&gt; text = set(text)
&gt;&gt;&gt; text_dict = set(text_dict)
&gt;&gt;&gt; text.intersection(text_dict)
{&apos;brandon&apos;, &apos;name&apos;, &apos;hello&apos;, &apos;my&apos;}
&gt;&gt;&gt; len(text.intersection(text_dict))
4
</code></pre><h2 id="%F0%9F%91%8B-conclusion">&#x1F44B; Conclusion</h2><p>Set theory is gnarly, and incredibly useful in not just competitive programming but all kinds of programming. We&#x2019;ve not only learnt the theory behind set theory but also how programming languages such as Python have implemented it.</p><p>However, looping through both of them ourselves is unruly. We&#x2019;d have to write a loop and keep track of it ourselves. Luckily, we can use set theories&apos; intersection function to do this for us.</p>]]></content:encoded></item><item><title><![CDATA[3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]]]></title><description><![CDATA[<p>Fancy watching this as a video instead? Click below:</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/WhPq-CPiLBE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="Why your open source project failed, and what to do about it"></iframe></figure><h2 id="introduction">Introduction</h2><p>I have around ~10k GitHub stars. I&#x2019;ve come up with a bullet-pointed actionable list of how to make open-source projects popular.</p><p>One of the projects I created had 67 lines of code and had only existed for 3</p>]]></description><link>https://skerritt.blog/make-popular-open-source-projects/</link><guid isPermaLink="false">62d3cad863e229003d521b99</guid><category><![CDATA[programming]]></category><category><![CDATA[Popular]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Fri, 23 Jun 2023 20:21:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1658037123931-7f384d639e37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDE5fHx8fHx8Mnx8MTY1ODA0NzAyOQ&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1658037123931-7f384d639e37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDE5fHx8fHx8Mnx8MTY1ODA0NzAyOQ&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]"><p>Fancy watching this as a video instead? Click below:</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/WhPq-CPiLBE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="Why your open source project failed, and what to do about it"></iframe></figure><h2 id="introduction">Introduction</h2><p>I have around ~10k GitHub stars. I&#x2019;ve come up with a bullet-pointed actionable list of how to make open-source projects popular.</p><p>One of the projects I created had 67 lines of code and had only existed for 3 days before it hit 1.7k stars.</p><p>Humans are predictable creatures when it comes to our attention. I&#x2019;ll show you data-backed actionable insights that can help you create popular software.</p><h2 id="why-bother-popular-projects-more-contributors-better-project">Why Bother? Popular Projects = More Contributors = Better Project</h2><p>What&#x2019;s the point in getting more GitHub stars? They mean nothing. You can&#x2019;t buy a coffee with exposure. If GitHub dies, so do the stars.</p><p>The problem with open source is the <a href="https://en.wikipedia.org/wiki/Network_effect?ref=skerritt.blog">network effect.</a> The more people that find your project, the more people that use it, the more that contribute to it and thus the better it becomes.</p><p>The better the project, the more popular it becomes. It&#x2019;s a self-fulfilling cycle.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-3.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="629" height="142" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-3.png 600w, https://skerritt.blog/content/images/2023/01/image-3.png 629w"><figcaption><a href="https://github.com/bee-san/Polymath/blob/main/media/populaross/loop4.svg?ref=skerritt.blog" rel="noopener noreferrer"><span style="white-space: pre-wrap;">Popularity -&gt; More Users -&gt; More Contributors -&gt; Better functionality -&gt; Popularity and so on</span></a></figcaption></figure><p>As this cycle continues, it becomes harder for it to continue. That&#x2019;s a blog post for another day. But first, let&#x2019;s talk about where we start.</p><p>To start us on this cycle we need popularity.</p><p>To get contributors to your project it has to be popular enough so people see it and contribute.</p><p>Creating a popular open-source project isn&#x2019;t just a want but a need.</p><p>If a project has contributors but no popularity, it&#x2019;s likely created by a company for internal use and was open-sourced.</p><p>Otherwise, only popular open-source projects have contributors.</p><h2 id="well-designed-readme">Well Designed README</h2><p><code>README.md</code> is the first thing anyone sees. Make sure to catch their eyes right away.</p><p>It&#x2019;s harder to gain traction based purely on the merit of the tool rather than on the presentation of the tool.</p><p>For frontend applications, you should focus more on the design of the frontend rather than the <code>README</code>. This is for CLI applications.</p><p>A well-designed README answers these questions succinctly:</p><ul><li>What does this do?</li><li>Does it solve my problem?</li><li>Does it solve my problem better than the competitors (if they exist) do?</li><li>How do I install it?</li><li>What are the basic commands I need to know?</li><li>Where can I go for more help?</li></ul><p>This is how a <code>README</code> answers these questions.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-4.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="800" height="2000" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-4.png 600w, https://skerritt.blog/content/images/2023/01/image-4.png 800w" sizes="(min-width: 720px) 720px"></figure><p>We&#x2019;ll go through each of these.</p><h2 id="create-a-header-summarising-your-project">Create a Header Summarising Your Project</h2><p>The first thing they see is your <code>README</code>. The first thing they see on the <code>README</code> is the header. Make it good.</p><p>The header is the combination of:</p><ul><li>Logo</li><li>Slogan (short description)</li><li>Badges</li><li>Quick Install</li><li>Quick Links (not always needed)</li></ul><h3 id="beautiful-logo-as-simple-as-canvacom">Beautiful Logo as simple as Canva.com</h3><p>The logo is the first thing users see and is the image used for social media sharing. When I first create a project, I&#x2019;ll use something from <a href="https://canva.com/?ref=skerritt.blog">Canva</a>.</p><p>Canva allows you to <strong>quickly</strong> create a logo from a template for free.</p><p>Go to Canva and search for &#x201C;Logo&#x201D;</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-5.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1063" height="643" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-5.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-5.png 1000w, https://skerritt.blog/content/images/2023/01/image-5.png 1063w" sizes="(min-width: 720px) 720px"></figure><p>And then just select one of the many logos you come across. Edit it if you want.</p><p>Typically, there are 2 things I look for in a logo:</p><ul><li>Coolness factor &#x1F60E;</li><li>Slogan</li></ul><p>I should look at the logo and think <em>&#x201D;wow, that&#x2019;s cool&#x201D;</em>.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/hash-search.gif" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="500" height="500"></figure><p>It&#x2019;s a gif! Isn&#x2019;t that cool? I made it on Canva in about ~45 seconds. ~30 seconds were spent searching for it!</p><p>Secondly, the slogan. The first thing people see will be the logo which contains the name and slogan, instantly they will know what the project is about.</p><p>For some of my larger projects, I hire a designer, specifically <a href="https://twitter.com/Vargnaar?ref=skerritt.blog">Varg</a>. Designers are great! Especially ones that can understand the project at hand, which aids in creating a well-conceived logo.</p><p>In short: don&#x2019;t spend too long picking a logo. If you&#x2019;re not hiring a designer, perhaps ~5 minutes playing around on Canva.</p><h3 id="slogan-description-of-your-project-in-1-simple-line">Slogan (description) of your project in 1 simple line</h3><p>When thinking about the design of your project, think about <em>how</em> people found it. There are 2 major ways people can find your project:</p><ol><li>Someone recommends it to them.</li><li>It&#x2019;s posted on Twitter / HackerNews / LinkedIn / other social media or news aggregators.</li></ol><p>When someone recommends something it&#x2019;s because that something solves their problem. This means that they already have an idea of <em>how</em> this project solves their problem, of what the project does.</p><p>When posted, Twitter will make a social card for it. This card is the title, description, and image.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-6.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="392" height="403"></figure><p>Both of the main methods of sharing your project include a description already. This means 2 things:</p><ol><li>We don&#x2019;t need to spend time describing <em>what</em> our project is in the <code>README</code>.</li><li>GitHub&#x2019;s Description will be used everywhere and is the first thing people see.</li></ol><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-7.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1600" height="685" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-7.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-7.png 1000w, https://skerritt.blog/content/images/2023/01/image-7.png 1600w" sizes="(min-width: 720px) 720px"></figure><p>One sentence or two will be adequate to explain our project in the <code>README</code>.</p><p>This is why I include the <em>quick install</em> section in the <code>README</code>. Users who come to your project already have an idea of what it is. Since they do, provide a way for them to quickly install it and try it out for themselves.</p><blockquote>&#x201C;Talk is cheap. Show me the code.&#x201D; - Linus Torvalds</blockquote><p>Good descriptions are hard to write. Very hard.</p><p>It needs to:</p><ul><li>Describe the project.</li><li>Be eye-catching.</li><li>Show why the user needs it.</li><li>Show why it&#x2019;s better than the rest.</li><li>Be easy enough for someone that only knows the subject matter in passing to understand.</li></ul><p>This is copywriting. It&#x2019;s an important skill to learn as copywriting is:</p><blockquote>Writing in such a way to convince someone to do something.</blockquote><p>My favourite resource is <a href="https://backlinko.com/copywriting-guide?ref=skerritt.blog">Brian Dean&#x2019;s Copywriting Guide</a>.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/gohugoio/hugo?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - gohugoio/hugo: The world&#x2019;s fastest framework for building websites.</div><div class="kg-bookmark-description">The world&#x2019;s fastest framework for building websites. - GitHub - gohugoio/hugo: The world&#x2019;s fastest framework for building websites.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">gohugoio</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://repository-images.githubusercontent.com/11180687/9d3d8200-abf2-11e9-803c-4cdfde0d22e5" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]"></div></a></figure><blockquote>The world&#x2019;s fastest framework for building websites.</blockquote><p>This explains what the project is well. It is:</p><ul><li>Succinct.</li><li>Answers the question &#x201C;Why are you better than the rest?&#x201D; with <em>&#x201D;world&#x2019;s fastest&#x201D;</em>.</li><li>Answers what it does, <em>&#x201D;framework for building websites.&#x201D;</em></li><li>Easy enough to understand for non-experts, <em>&#x201D;building websites&#x201D;</em>.</li><li>Uses eye-catching words such as <em>&#x201D;worlds largest&#x201D;</em> and the succinctness imply &#x201C;we can read this, it&#x2019;ll only take a second of our time to process this.&#x201D;</li></ul><p>You should spend a few weeks experimenting with the description on-and-off.</p><p>Come up with many descriptions, about ~20. And continually improve upon it. When you lie down in bed, think <em>&#x201D;If I had never seen my project before, what would I want to see to make me use it?&#x201D;</em>.</p><p>The description is the hardest, but most important part of the whole design. <strong>It&#x2019;s the first thing people see.</strong> Invest time into this. Learn copywriting. Even when you think it&#x2019;s perfect, it can always be improved.</p><p>Ask your users what they think of it. Iterate until you can no longer iterate.</p><h3 id="badges">Badges</h3><p>Badges are links/images that sum up the project.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-8.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="636" height="81" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-8.png 600w, https://skerritt.blog/content/images/2023/01/image-8.png 636w"></figure><p>They explain where to find documentation, is the current branch stable? How clean is the code?</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-9.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1365" height="130" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-9.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-9.png 1000w, https://skerritt.blog/content/images/2023/01/image-9.png 1365w" sizes="(min-width: 720px) 720px"></figure><p>How active is the project? How many downloads? The license? Any chatrooms? Mostly, badges are just cool stickers you can include. I like reading them, but some people may not. You can find a list of badges on <a href="http://shields.io/?ref=skerritt.blog">shields.io</a>.</p><h3 id="quick-installation-guide">Quick Installation guide</h3><p>The user understands what the application does from seeing it in the social cards or being told by a friend.</p><p>Sometimes, they want to install it as fast as possible to play around.</p><blockquote>&#x201C;Talk is cheap, show me the code.&#x201D; - Linus Torvalds</blockquote><p>The quick install guide allows users to install the software immediately.</p>
<!--kg-card-begin: html-->
<table style="box-sizing: border-box; display: table; width: 720px; border-collapse: collapse; border-spacing: 0px; overflow: auto; word-break: keep-all; margin: 25px 0px 32px; font-size: 0.9em; font-family: sans-serif; min-width: 400px; box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 20px; color: rgba(0, 0, 0, 0.88); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><thead style="box-sizing: border-box;"><tr style="box-sizing: border-box; background-color: rgb(0, 152, 121); color: rgb(255, 255, 255); text-align: left;"><th style="box-sizing: border-box; padding: 12px 8px; border-top: thin solid rgb(153, 153, 153) !important; border-right: thin solid rgb(153, 153, 153) !important; border-bottom: 1px solid var(--border); border-left: thin solid rgb(153, 153, 153) !important; border-image: initial !important; min-width: 80px; line-height: 1.5; font-size: 14px; text-align: start;"><p align="center" style="box-sizing: border-box; margin-top: 0px; margin-bottom: var(--content-gap);"><a href="https://pypi.org/project/ciphey?ref=skerritt.blog" style="box-sizing: border-box; color: var(--primary); text-decoration: none; box-shadow: 0px 1px 0px;">&#x1F40D; Python</a></p></th><th style="box-sizing: border-box; padding: 12px 8px; border-top: thin solid rgb(153, 153, 153) !important; border-right: thin solid rgb(153, 153, 153) !important; border-bottom: 1px solid var(--border); border-left: thin solid rgb(153, 153, 153) !important; border-image: initial !important; min-width: 80px; line-height: 1.5; font-size: 14px; text-align: start;"><p align="center" style="box-sizing: border-box; margin-top: 0px; margin-bottom: var(--content-gap);"><a href="https://pypi.org/project/ciphey?ref=skerritt.blog" style="box-sizing: border-box; color: var(--primary); text-decoration: none; box-shadow: 0px 1px 0px;">&#x1F40B; Docker (Universal)</a></p></th></tr></thead><tbody style="box-sizing: border-box;"><tr style="box-sizing: border-box; border-bottom: thin solid rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-top: thin solid rgb(153, 153, 153) !important; border-right: thin solid rgb(153, 153, 153) !important; border-bottom: 1px solid var(--border); border-left: thin solid rgb(153, 153, 153) !important; border-image: initial !important; min-width: 80px; line-height: 1.5;"><p align="center" style="box-sizing: border-box; margin-top: 0px; margin-bottom: var(--content-gap);"><img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/python.png" style="box-sizing: border-box; display: block; max-width: 100%; margin: auto; text-align: center; transition: transform 0.5s ease 0s; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204) rgb(136, 136, 136) rgb(136, 136, 136) rgb(204, 204, 204); background-color: rgb(252, 252, 252); padding: 1px; margin-block: 10px; border-radius: 4px;" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]"></p></td><td style="box-sizing: border-box; padding: 12px 8px; border-top: thin solid rgb(153, 153, 153) !important; border-right: thin solid rgb(153, 153, 153) !important; border-bottom: 1px solid var(--border); border-left: thin solid rgb(153, 153, 153) !important; border-image: initial !important; min-width: 80px; line-height: 1.5;"><p align="center" style="box-sizing: border-box; margin-top: 0px; margin-bottom: var(--content-gap);"><img src="https://github.com/Ciphey/Ciphey/raw/master/Pictures_for_README/docker.png" style="box-sizing: border-box; display: block; max-width: 100%; margin: auto; text-align: center; transition: transform 0.5s ease 0s; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204) rgb(136, 136, 136) rgb(136, 136, 136) rgb(204, 204, 204); background-color: rgb(252, 252, 252); padding: 1px; margin-block: 10px; border-radius: 4px;" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]"></p></td></tr><tr style="box-sizing: border-box; border-bottom: 2px solid rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-top: thin solid rgb(153, 153, 153) !important; border-right: thin solid rgb(153, 153, 153) !important; border-bottom: 1px solid var(--border); border-left: thin solid rgb(153, 153, 153) !important; border-image: initial !important; min-width: 80px; line-height: 1.5;"><code style="box-sizing: border-box; direction: ltr; margin: auto 0px; padding: 4px 6px; font-family: Menlo, Monaco, " courier new", courier, monospace; font-size: 0.78em; line-height: 1.5; background: var(--code-bg); border-radius: 2px;">python3 -m pip install ciphey --upgrade</code></td><td style="box-sizing: border-box; padding: 12px 8px; border-top: thin solid rgb(153, 153, 153) !important; border-right: thin solid rgb(153, 153, 153) !important; border-bottom: 1px solid var(--border); border-left: thin solid rgb(153, 153, 153) !important; border-image: initial !important; min-width: 80px; line-height: 1.5;"><code style="box-sizing: border-box; direction: ltr; margin: auto 0px; padding: 4px 6px; font-family: Menlo, Monaco, " courier new", courier, monospace; font-size: 0.78em; line-height: 1.5; background: var(--code-bg); border-radius: 2px;">docker run -it --rm remnux/ciphey</code></td></tr></tbody></table>
<!--kg-card-end: html-->
<p>Users do not need to scour the <code>README</code> for information on installation if they are already knowledgeable and want to use the project.</p><p>The style above is clean. The package manager&#x2019;s name, the logo of the operating system and a short installation to copy/paste.</p><h3 id="quick-links">Quick Links</h3><p>This isn&#x2019;t required in all READMEs.</p><p>Linking to all the resources the user needs in one neat place allows the user to quickly understand <em>anything</em> they want.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-10.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1124" height="63" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-10.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-10.png 1000w, https://skerritt.blog/content/images/2023/01/image-10.png 1124w" sizes="(min-width: 720px) 720px"></figure><p>The order of these matters. As the user reads left-to-right (assuming English <code>README</code>), the further away items are the less likely they will see it. You want them to see your Twitter first? Include that at the first item.</p><p>While this is a flat list separated by pipes, it is an ordered list in the sense that users will only read so far.</p><p>I include my quick links at the top of the page, above the fold (the logo).</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-11.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="850" height="251" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-11.png 600w, https://skerritt.blog/content/images/2023/01/image-11.png 850w" sizes="(min-width: 720px) 720px"></figure><p>The user will already have a rough idea of what the project is. They may only want 3 things from the README:</p><ol><li>Documentation.</li><li>Support (the Discord link).</li><li>The Installation Guide.</li></ol><p>By being at the top, we reduce the friction of finding them.</p><h3 id="example-images-to-show-off-your-project">Example Images to show off your project</h3><p>The header is also a great place to show <em>how</em> your project works. You can use gifs (discussed later in more depth) or images.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-12.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1221" height="507" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-12.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-12.png 1000w, https://skerritt.blog/content/images/2023/01/image-12.png 1221w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/microsoft/Bringing-Old-Photos-Back-to-Life?ref=skerritt.blog"><span style="white-space: pre-wrap;">Bringing-Old-Photos-Back-to-Life</span></a></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-13.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1227" height="660" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-13.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-13.png 1000w, https://skerritt.blog/content/images/2023/01/image-13.png 1227w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/bee-san/Polymath/blob/main/media/populaross/depixi.png?ref=skerritt.blog" rel="noopener noreferrer"><span style="white-space: pre-wrap;">Pixelated text which is recovered to non-pixelated next to the original text</span></a></figcaption></figure><p>This depends on your project, but having images in your header may make sense.</p><p><strong>Inspiration for designing your header</strong> Let&#x2019;s look at some inspiration</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-14.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1689" height="1670" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-14.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-14.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/01/image-14.png 1600w, https://skerritt.blog/content/images/2023/01/image-14.png 1689w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/Ciphey/Ciphey?ref=skerritt.blog"><span style="white-space: pre-wrap;">Ciphey/Ciphey: &#x26A1; Automatically decrypt encryptions without knowing the key&#x26A1;</span></a></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-15.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1487" height="1668" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-15.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-15.png 1000w, https://skerritt.blog/content/images/2023/01/image-15.png 1487w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/rustscan/rustscan?ref=skerritt.blog"><span style="white-space: pre-wrap;">RustScan/RustScan: &#x1F916; The Modern Port Scanner &#x1F916;</span></a><span style="white-space: pre-wrap;"> /</span></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-16.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1224" height="966" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-16.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-16.png 1000w, https://skerritt.blog/content/images/2023/01/image-16.png 1224w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/cytopia/pwncat?ref=skerritt.blog"><span style="white-space: pre-wrap;">cytopia/pwncat: pwncat - netcat on steroids</span></a></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-17.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="958" height="418" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-17.png 600w, https://skerritt.blog/content/images/2023/01/image-17.png 958w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/gohugo/hugo?ref=skerritt.blog"><span style="white-space: pre-wrap;">gohugoio/hugo: The world&#x2019;s fastest framework for building websites.</span></a></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-20.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1240" height="1119" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-20.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-20.png 1000w, https://skerritt.blog/content/images/2023/01/image-20.png 1240w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/alacritty/alacritty?ref=skerritt.blog"><span style="white-space: pre-wrap;">alacritty/alacritty: A terminal emulator</span></a></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-18.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1220" height="962" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-18.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-18.png 1000w, https://skerritt.blog/content/images/2023/01/image-18.png 1220w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/starship/starship?ref=skerritt.blog"><span style="white-space: pre-wrap;">starship/starship: &#x2604;&#x1F30C;&#xFE0F; Customizable prompt for any shell!</span></a></figcaption></figure><h2 id="what-is-this-describing-your-project-succinctly">What Is This? Describing Your Project Succinctly.</h2><p>This section explains the features of your product.</p><p>Short explanations. A gif that demonstrates your project. Essential features you think someone would want to see.</p><p>Look at the Starship prompt.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-21.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1220" height="962" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-21.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-21.png 1000w, https://skerritt.blog/content/images/2023/01/image-21.png 1220w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/starship/starship?ref=skerritt.blog"><span style="white-space: pre-wrap;">starship/starship: &#x2604;&#x1F30C;&#xFE0F; Customizable prompt for any shell!</span></a></figcaption></figure><p>They have a table with 2 columns but without borders. In the left column is the list of essential features. Each feature is bolded with a short explanation.</p><ul><li><strong>Bold feature</strong>: I am explaining the feature</li></ul><p>And in the right column is a gif showing how the program works, preferably detailing the features mentioned.</p><p>To create a gif of a CLI app, use <a href="https://github.com/faressoft/terminalizer?ref=skerritt.blog">Terminalizer</a>. Clean up your terminal before you record, as it can look messy.</p><p>You can also use Asciienma:</p><ol><li>Install <a href="https://asciinema.org/?ref=skerritt.blog">asciinema</a> and <a href="https://github.com/marionebl/svg-term-cli?ref=skerritt.blog">svg-term-cli</a>.</li></ol><p>2. Record with asciinema:</p><pre><code>asciinema rec demo.cast</code></pre><p>This records the session in the asciicast v2 plaintext file format.</p><p>3. Convert the .cast file to .svg with svg-term-cli:</p><pre><code>svg-term --in demo.cast --out demo.svg --window --width 80 --height 22 --no-optimize</code></pre><p>You probably want to play around with width and height. <code>--window</code> adds a fake OS window around the terminal session. I found that no-optimize fixed some weird font rendering issues on my macOS.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F47D;</div><div class="kg-callout-text">This is the method I use! You can see me using it in <a href="https://github.com/bee-san/Ares/tree/main/images?ref=skerritt.blog#steps-to-make-the-gifs">this repo and here&apos;s some documentation I wrote on it</a>.</div></div><p>When thinking of what features to show, <strong>do not show them all.</strong> Only show the features that the user wants to see. And in words that a user can understand.</p><h2 id="x-vs-y-comparisons-with-competitors">X vs Y, Comparisons With Competitors</h2><p>If your project is competing with a lot of other projects, you&#x2019;re going to need to show the user exactly why they should use your project over the competitors.</p><p>Convincing someone to leave their current tool for yours is hard. Make it as easy as possible for them to see the advantages over their current tooling.</p><p>In <a href="https://www.goodreads.com/book/show/10127019-the-lean-startup?from_search=true&amp;from_srp=true&amp;qid=zKpCYP3FEY&amp;rank=1&amp;ref=skerritt.blog">The Lean Startup</a> the author talks about why at the beginning of a startup we should focus on the early adopters over the average customers.</p><blockquote>&#x201C;The point is not to find the average customer but to find <strong>early adopters</strong>: the customers who feel the need for the product most acutely. Those customers tend to be more forgiving of mistakes and are especially eager to give feedback.&#x201D;</blockquote><p>The early adopters are those that wouldn&#x2019;t mind switching out their current tooling for a less tested, less mainstream option if it means it has better functionality.</p><p>The only way to get the average customer to use your product is:</p><ul><li>No competitors must exist.</li><li>Their current solution to the problem is extremely convoluted compared to yours.</li></ul><p>Otherwise, your best bet is to appeal to the early adopters and overtime slowly appeal to the average customer as your project becomes more mainstream.</p><p>The easiest way to compare your projects to others is to include a table of popular features. Use statistics here. It&#x2019;s harder to believe words than it is numbers, even if the words are just as truthful as the numbers.</p><p>For Ciphey we compared our program to our largest possible competitor, CyberChef&#x2019;s Magic function.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/01/image-22.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="754" height="1158" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-22.png 600w, https://skerritt.blog/content/images/2023/01/image-22.png 754w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://github.com/ciphey/ciphey?ref=skerritt.blog#-ciphey-vs-cyberchef"><span style="white-space: pre-wrap;">CyberChef vs Ciphey</span></a></figcaption></figure><p>You can see we used gifs to demonstrate this. We explain how long each one takes and the setup of both, which can all be seen in the gifs.</p><p>We also leave footnotes on some things. Such as gifs loading at different times, the function (at the time) failing to decode.</p><p>Later on, we compare again with a table this time of features.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-23.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="686" height="289" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-23.png 600w, https://skerritt.blog/content/images/2023/01/image-23.png 686w"></figure><h2 id="create-great-documentation">Create Great Documentation</h2><p>Do not put all your documentation into your <code>README</code> because:</p><ul><li>It&#x2019;s harder to update.</li><li>It&#x2019;s harder for users to find things.</li><li>It makes the <code>README</code> unbearably long and ugly.</li></ul><p>We don&#x2019;t write all of our code in one file, why have all of our documentation in our README?</p><p>Don&#x2019;t make the documentation section long. Since we have already explained how to install it quickly, we should show:</p><ul><li>How to run the program.</li><li>How to find the documentation.</li><li>How to find support.</li></ul><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-24.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1218" height="1649" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-24.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-24.png 1000w, https://skerritt.blog/content/images/2023/01/image-24.png 1218w" sizes="(min-width: 720px) 720px"></figure><p>I included a gif here showing all the different ways there are to run Ciphey. Gifs are magical and easy to make.</p><h2 id="contributing-thanking-welcoming-contributors">Contributing, Thanking &amp; Welcoming Contributors</h2><p>The final section is about contributing.</p><ol><li>How to contribute.</li><li>Thanking past contributors.</li></ol><p>We need contributors to our project to fulfil the cycle.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-26.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="629" height="142" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-26.png 600w, https://skerritt.blog/content/images/2023/01/image-26.png 629w"></figure><p>Therefore, our README needs to display how to contribute.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-25.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1200" height="1143" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-25.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-25.png 1000w, https://skerritt.blog/content/images/2023/01/image-25.png 1200w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/media/populaross/contrib.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy"></figure><p>A short paragraph describing how to contribute, where to ask for help if they are stuck, the <code>contributing.md</code> file and any potential rewards for contributing (name added to the <code>README</code> and the chance to work on a growing project).</p><p>And then you want to thank your contributors. We use <a href="https://github.com/all-contributors/all-contributors?ref=skerritt.blog">all-contributors</a> which makes it easy to thank them. It shows their profile picture, a link to their websites along with emoji defining <em>what</em> they did.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-27.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1200" height="1379" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-27.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-27.png 1000w, https://skerritt.blog/content/images/2023/01/image-27.png 1200w" sizes="(min-width: 720px) 720px"></figure><h2 id="conclusion-of-designing-the-readme">Conclusion of Designing the README </h2><p>Design is subjective and you may like something, or you may not. It&#x2019;s down to you to decide on what looks good.</p><p>I hope the design principles I shared, along with the <code>README</code>s included here will inspire you to create something beautiful.</p><p>One thing I didn&#x2019;t talk about here is creating documentation. It is your job as a programmer to create documentation. Your project is not done until it has documentation. You can use <a href="https://docs.github.com/en/free-pro-team@latest/github/building-a-strong-community/about-wikis?ref=skerritt.blog">GitHub Wiki</a> and <a href="https://www.python.org/dev/peps/pep-0257/?ref=skerritt.blog">DocStrings</a> to automatically generate <em>some</em> documentation (you&#x2019;ll still need to write documentation for installation, usage, etc).</p><p>Remember &#x2014; the <code>README</code> is one of the most important parts of an open-source project (along with the documentation).</p><h2 id="creating-something-people-want">Creating Something People Want</h2><p>A good <code>README</code> will get people interested, and a working project that solves their problems will get people talking.</p><p>This chapter is based on <a href="https://en.wikipedia.org/wiki/Zero_to_One?ref=skerritt.blog">Zero to One by Peter Thiel</a>, but will feature inspiration from other places.</p><blockquote>&#x201C;Every moment in business happens only once. The next Bill Gates will not build an operating system. The next Larry Page or Sergey Brin won&#x2019;t make a search engine. And the next Mark Zuckerberg won&#x2019;t create a social network. If you are copying these guys, you aren&#x2019;t learning from them.&#x201D;</blockquote><h2 id="problem-first-product-second">Problem First, Product Second</h2><p>For your project to grow, it has to solve a problem. It&#x2019;s better to find a solution to a problem that people have rather than create a project for the sake of it.</p><p>Let&#x2019;s compare 2 ideas.</p><ol><li>A recipe app</li><li>A digital platform for artists to share their work, get feedback and start selling to gallery owners.</li></ol><p>The first one doesn&#x2019;t solve any problems. There are millions of recipe apps in the world and unless there is something <strong>truly</strong> unique it won&#x2019;t take off.</p><p>The second one is a unique &amp; novel idea that aims to solve the problem of:</p><blockquote>&#x201C;I&#x2019;m an artist wanting to get paid for my work and improve.&#x201D;</blockquote><p>We have a problem, artists not getting paid, and we solve the problem.</p><p>Some people come up with the project first, but doing this means:</p><ul><li>We aren&#x2019;t solving one specific problem from the start.</li><li>We don&#x2019;t have a well-defined target market.</li><li>It&#x2019;s likely already been done before.</li></ul><p>As Walter Isaacson said in <a href="https://www.goodreads.com/book/show/21856367-the-innovators?ref=skerritt.blog">The Innovators:</a></p><blockquote>&#x201C;But the main lesson to draw from the birth of computers is that innovation is usually a group effort, involving collaboration between visionaries and engineers and that creativity comes from drawing on many sources. Only in storybooks do inventions come like a thunderbolt, or a lightbulb popping out of the head of a lone individual in a basement or garret or garage.&#x201D;</blockquote><p>It&#x2019;s unlikely for our project to be innovative if we don&#x2019;t solve a small problem first. In the same book, Isaacson says:</p><blockquote>&#x201C;Progress comes not only in great leaps but also from hundreds of small steps.&#x201D;</blockquote><p>Solving the problem will bring us closer to a unique &amp; novel project.</p><h2 id="living-with-the-problem">Living With the Problem</h2><p>You cannot solve a problem you do not have. In <a href="https://www.goodreads.com/book/show/10127019-the-lean-startup?ref=skerritt.blog">The Lean Startup</a>, Eric Ries states:</p><blockquote>&#x201C;In my Toyota interviews, when I asked what distinguishes the Toyota Way from other management approaches, the most common first response was genchi gembutsu&#x2014;whether I was in manufacturing, product development, sales, distribution, or public affairs. <strong>You cannot be sure you really understand any part of any business problem unless you go and see for yourself firsthand</strong>. It is unacceptable to take anything for granted or to rely on the reports of others.&#x201D;</blockquote><p>Unless you have the problem, you cannot effectively solve the problem.</p><p>It also helps with idea generation. Pay attention to the minor inconveniences in your life, in the lives of people around you and build products that solve those problems.</p><p>It&#x2019;s a lot easier to observe the problems present in your own life than it is to generate random ideas that might work.</p><p>If you have a problem, you know 2 things:</p><ol><li>The problem exists.</li><li>Other people have the problem.</li></ol><p>The first point is important. <strong>Many people create solutions for problems that do not exist.</strong></p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/LqTdoN4y36U?start=2&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="Potato Doctor"></iframe></figure><p>This product essentially injects the potato with oil and other foods. This problem does not exist. No one has ever had this problem. If you watch the video, you can see that the Potato Doctor cuts the potato open. What is the point? There isn&#x2019;t one.</p><p>The second point is less obvious, but a good indicator. Humans are not unique. We mostly share the same problems. If the problem directly affects my life, I know that it must affect other people too.</p><h2 id="finding-problems-in-communities">Finding Problems in Communities</h2><p>You don&#x2019;t have to be the one to find the problem, others can too. If you pay attention to a community, these people will reveal the problems they are facing.</p><p>Listening to a community exponentially grows your rate of ideas vs being on your own.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-28.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1024" height="576" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-28.png 600w, https://skerritt.blog/content/images/size/w1000/2023/01/image-28.png 1000w, https://skerritt.blog/content/images/2023/01/image-28.png 1024w" sizes="(min-width: 720px) 720px"></figure><p>The more people there are, the more you listen, the more ideas you can generate over time compared to thinking on your own.</p><p>Build a minimal viable product that solves the problem the community is facing.</p><blockquote>A <strong>minimum viable product</strong>, or <strong>MVP</strong>, is a <strong>product</strong> with enough features to attract early-adopter customers and validate a <strong>product</strong> idea early in the <strong>product</strong> development cycle.</blockquote><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-29.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="800" height="450" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-29.png 600w, https://skerritt.blog/content/images/2023/01/image-29.png 800w" sizes="(min-width: 720px) 720px"></figure><p>Share with the community. Measure its effectiveness, learn how to do better and re-build it (or add more) to improve upon it.</p><p>Over time, it will eventually leak out of the community into other similar communities.</p><p>You have around 2 weeks before you lose motivation to work on something. Create the smallest possible minimum viable product that the community can use. Their thanks, if provided, will give you the motivation to continue working on it.</p><h2 id="solving-the-problem-well">Solving the Problem Well</h2><p>Here&#x2019;s the thing.</p><ul><li>You have a problem you can solve.</li><li>You have a community that&#x2019;ll help you solve this problem and provides feedback.</li></ul><p>But that doesn&#x2019;t mean your problem is solved <em>well</em>. Take a look at <a href="https://en.wikipedia.org/wiki/Juicero?ref=skerritt.blog">Juicero</a>. Juicero solved a problem that many people have.</p><p>We want to create our juice drinks, but to do that we have to:</p><ul><li>Buy Fruit &amp; Vegetables.</li><li>Wash them.</li><li>Cut them.</li><li>Juice them.</li><li>Clean up.</li></ul><p>Juicero&#x2019;s solution was to (ignoring hardware):</p><ul><li>Insert packet into Juicero to get the juice.</li></ul><p>This is a good idea, but it was poorly executed.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/mlfAHrpm3C8?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="Juicero: the $400 juicer that couldn&apos;t make juice"></iframe></figure><p>There are many talks about why Juicero failed &#x2014; all out of the scope of this article.</p><p>The point is that you could have a great idea, but if it&#x2019;s poorly executed it may have too many downsides to be used as the solution.</p><p>The way to solve this is via the minimum viable product loop. Instead of spending 3 years creating a project, we release it as soon as possible, gather feedback, improve and loop.</p><p>We are continuously heading towards what people want, and each iteration will solve the problem better than the last. If it doesn&#x2019;t, the next iteration we solve the problem differently and so on.</p><h2 id="getting-the-word-out">Getting the Word Out</h2><p>If we never show off our project, why would we expect anyone to see it? It&#x2019;s not good enough to build it and hope they come. We have to get the word out.</p><p>The good news is that if you&#x2019;ve been following along in Creating Something People Want we already have the word out. The community we are in know about the project and use it.</p><p>That helps us immensely. Going from 10 GitHub stars to 100 is easy. Going from 0 to 1 is hard.</p><p>Once we get a few stars we will get more stars. Stars beget stars &#x2B50;.</p><h2 id="sharing-with-a-community">Sharing With a Community</h2><p>If we have been following the Build, Measure, Learn loop and regularly publishing minimal viable products then we will already have the word out in our community.</p><p>When it comes time to publish, make sure your community knows that it&#x2019;s the first <strong>real</strong> release. They&#x2019;d be more likely to share with their friends this way.</p><h2 id="news-aggregators">News Aggregators</h2><p>Your next port of call is news aggregators. These are places that collate news. You should post to:</p><ul><li>Subreddit of your choosing.</li><li>HackerNews.</li><li>Lobste.rs.</li></ul><p>Do not read the comments. Those places are incredibly toxic and can&#x2019;t see a good product even if it <a href="https://news.ycombinator.com/item?id=8863&amp;ref=skerritt.blog">hit them in the face</a>.</p><h2 id="awesome-lists">Awesome Lists</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/01/image-30.png" class="kg-image" alt="3 Tips For Making a Popular Open Source Project in 2024 [Ultimate Guide]" loading="lazy" width="1000" height="700" srcset="https://skerritt.blog/content/images/size/w600/2023/01/image-30.png 600w, https://skerritt.blog/content/images/2023/01/image-30.png 1000w" sizes="(min-width: 720px) 720px"></figure><p>An <a href="https://github.com/sindresorhus/awesome?ref=skerritt.blog">Awesome list</a> is a list of awesome things about some topic. There are lists such as:</p><ul><li>Rust</li><li>Python</li><li>Hacking</li><li>Web</li></ul><p>And more.</p><p>Find some lists that apply to you and submit PRs. In the worst case, they don&#x2019;t accept it.</p><h2 id="github-trending">GitHub Trending</h2><p>If all goes well, you should hit GitHub trending at some point. This will provide monumental traffic.</p><p>Once you hit trending, pay attention to social media and thank anyone that shares your project. If they follow you they may re-tweet your project again in the future.</p><p>This is the snowball effect. You need about ~50 stars to hit the trending page for your language, ~100 stars to hit the overall trending. Once you do this, trending will give you more stars and it will continually snowball.</p><h2 id="leverage-an-existing-following-or-past-popularity">Leverage an Existing Following or Past Popularity</h2><p>The easiest way to gain stars is by leveraging your existing following. Post on social media, other GitHub repos and the likes.</p><h2 id="conclusionthrow-the-rule-book-away">Conclusion - Throw the Rule Book Away</h2><p>Like all things, this is not an exact science, more like art. And you can&#x2019;t become good at art by following other people&apos;s guidance. You&#x2019;ve got to discover your unique style.</p><p>The Mona Lisa was painted once, but the thousands of people that painted the Mona Lisa afterwards were never recognised.</p><p>I suggest you throw some of the rules away, and experiment yourself. Create new rules and understand what works for you.</p><p>What works for me, won&#x2019;t necessarily work for you. So go ahead, throw the rule book away!</p><p>Let&#x2019;s go over some things we learnt.</p><ul><li>Well-designed READMEs are essential.</li><li>Creating something people want.</li><li>Get the word out there.</li><li>Discover your unique style and what works for you.</li></ul>]]></content:encoded></item><item><title><![CDATA[Packaging Your Rust Code]]></title><description><![CDATA[<p>I recently went through the trouble of distributing a Rust package. I wished that there was a simple guide on distributing one package to many platforms, so I wrote this guide.</p><p>Follow me as we publish my package, RustScan, to multiple distributions.</p><h2 id="semantic-versioning">Semantic Versioning</h2><p>Semantic Versioning is a system defining</p>]]></description><link>https://skerritt.blog/packaging-your-rust-code/</link><guid isPermaLink="false">62dbf9de1e7152003d2c39f3</guid><category><![CDATA[rust]]></category><category><![CDATA[programming]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Thu, 22 Jun 2023 10:39:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1528041119984-da3a9f8d04d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fGRpc25leXxlbnwwfHx8fDE2ODc0MzM3NjR8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1528041119984-da3a9f8d04d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fGRpc25leXxlbnwwfHx8fDE2ODc0MzM3NjR8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Packaging Your Rust Code"><p>I recently went through the trouble of distributing a Rust package. I wished that there was a simple guide on distributing one package to many platforms, so I wrote this guide.</p><p>Follow me as we publish my package, RustScan, to multiple distributions.</p><h2 id="semantic-versioning">Semantic Versioning</h2><p>Semantic Versioning is a system defining how to write version numbers. The 3 numbers are:</p><pre><code>Major.Minor.Bugs
</code></pre><p>If you have fixed some bugs, increment the bugs counter.</p><p>If you have added a minor feature, increment the minor counter.</p><p>If you have done something major, increment the major counter.</p><p>We can signify whether a release is still being rested or not by adding &#x201C;rc&#x201D; (release candidate) to the end of the version. &#x201C;5.0.0rc1&#x201D; signifies &#x201C;release candidate 1&#x201D; which means this is the first public testing release of version 5.0.0.</p><h2 id="cargo">Cargo</h2><p>Cargo is a package registry system for Rust. Imagine it as PyPi (Pip for Python) or NPM (for JavaScript).</p><p>As a rustacean, you may have heard of this &#x2013; and even used it to download packages yourself. So let&#x2019;s skip right to the good part.</p><p>Before publishing to Cargo, we need to make sure our <code>cargo.toml</code> file has the required information.</p><p>There are 3 things we need:</p><ul><li>Name</li></ul><p>The name of our project.</p><ul><li>Description</li></ul><p>Describe what the project does.</p><ul><li>License</li></ul><p>What license do you use? Specifically, we need to use a license identification code. View the <a href="https://spdx.org/licenses/?ref=skerritt.blog">Linux Foundation&#x2019;s SPDX</a> website for all the license identification codes.</p><p>However, you will probably want more than these for your package. Some good ones are:</p><ul><li>Readme</li></ul><p>The location of your README file, which is used to fill out the README on the Cargo website.</p><ul><li>Keywords</li></ul><p>These are tags for your project. When a user searches a keyword such as &#x201C;sewing&#x201D;, and your project has that keyword, your project will come up in the search results.</p><p>This is <a href="https://github.com/brandonskerritt/RustScan?ref=skerritt.blog">RustScan&#x2019;s</a><code>Cargo.toml</code>:</p><pre><code>[package]
name = &quot;rustscan&quot;
version = &quot;1.0.1&quot;
authors = [&quot;Autumn &lt;my_email@skerritt.blog&gt;&quot;]
edition = &quot;2018&quot;
description = &quot;Faster Nmap Scanning with Rust&quot;
homepage = &quot;https://github.com/bee-san/rustscan&quot;
repository = &quot;https://github.com/bee-san/rustscan&quot;
license = &quot;MIT&quot;
keywords = [&quot;port&quot;, &quot;scanning&quot;, &quot;nmap&quot;]
categories = [&quot;command-line-utilities&quot;]
readme=&quot;README.md&quot;
</code></pre><p>For more information on the manifest file, look here: </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://doc.rust-lang.org/cargo/reference/manifest.html?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The Manifest Format - The Cargo Book</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://doc.rust-lang.org/cargo/favicon.png" alt="Packaging Your Rust Code"><span class="kg-bookmark-author">The Cargo Book</span></div></div></a></figure><p>Now we&#x2019;re ready to publish! Go to the <a href="https://crates.io/?ref=skerritt.blog">Crates.io</a> website and register an account. Then, go into the settings and create a new API key.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.39.23.png" class="kg-image" alt="Packaging Your Rust Code" loading="lazy" width="2000" height="778" srcset="https://skerritt.blog/content/images/size/w600/2023/06/Screenshot-2023-06-22-at-12.39.23.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/Screenshot-2023-06-22-at-12.39.23.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/06/Screenshot-2023-06-22-at-12.39.23.png 1600w, https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.39.23.png 2026w" sizes="(min-width: 720px) 720px"></figure><p>Now in a terminal, execute <code>cargo login &lt;API_KEY&gt;</code>. You&#x2019;re now logged into Crates.io and can publish!</p><p>Build your Rust package using the release profile, which optimises it at the highest level Rust can provide:</p><pre><code>cargo build --release
</code></pre><p>And then publish it.</p><pre><code>cargo publish
</code></pre><p>Ta-da! Your package is now available on the Crates.io website, and can be installed with <code>cargo &lt;your_package_name&gt;</code>.</p><h1 id="windows-or-any-platform-with-binaries">Windows (or any platform with binaries)</h1><p>You can use Cargo Dist for this:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/axodotdev/cargo-dist?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - axodotdev/cargo-dist: &#x1F4E6; shippable application packaging for Rust</div><div class="kg-bookmark-description">&#x1F4E6; shippable application packaging for Rust. Contribute to axodotdev/cargo-dist development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Packaging Your Rust Code"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">axodotdev</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/ab0a59a04f0787c31cb7ae19c1575c3a5fb87061b3e6d0dd93e092eac2046539/axodotdev/cargo-dist" alt="Packaging Your Rust Code"></div></a></figure><p>You can generate the CI using:</p><pre><code>cargo dist init --ci=github</code></pre><p>This creates a bunch of files (see pull request below)</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/bee-san/Ares/pull/226/files?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Implement cargo dist by SkeletalDemise &#xB7; Pull Request #226 &#xB7; bee-san/Ares</div><div class="kg-bookmark-description">Generated cargo dist workflow using cargo dist init --ci=github The workflow will draft a new release and automatically add binaries to it whenever we make a new GitHub tag that looks like a versi&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Packaging Your Rust Code"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">bee-san</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://avatars.githubusercontent.com/u/29117662?s=400&amp;v=4" alt="Packaging Your Rust Code"></div></a></figure><p>It works, and it makes binaries for all of the major operating systems.</p><div class="kg-card kg-callout-card kg-callout-card-pink"><div class="kg-callout-emoji">&#x1F920;</div><div class="kg-callout-text">Below includes more manual processes / fine-grained processes if you plan to submit your package to package repositories or whatnot. <br><br>If you don&apos;t care about them so much and just want to hand out binaries, you can stop reading here.</div></div><h2 id="homebrew">Homebrew</h2><p>Homebrew is a package manager used by Mac OS users but can is also used on Linux.</p><p>Unfortunately, I found the documentation to be lacklustre in explaining how to get a package into Homebrew.</p><p>Let&#x2019;s assume we are using GitHub to store our code.</p><p>Homebrew expects an <code>TAR</code> archive. To get this, we create a new release on GitHub.</p><p>On the GitHub repo&#x2019;s homepage, click &#x201C;Releases&#x201D; on the right-hand side menu.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.40.11.png" class="kg-image" alt="Packaging Your Rust Code" loading="lazy" width="738" height="344" srcset="https://skerritt.blog/content/images/size/w600/2023/06/Screenshot-2023-06-22-at-12.40.11.png 600w, https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.40.11.png 738w" sizes="(min-width: 720px) 720px"></figure><p>You should be taken to this page. Click &#x201C;Draft a new release&#x201D;.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.40.26.png" class="kg-image" alt="Packaging Your Rust Code" loading="lazy" width="956" height="208" srcset="https://skerritt.blog/content/images/size/w600/2023/06/Screenshot-2023-06-22-at-12.40.26.png 600w, https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.40.26.png 956w" sizes="(min-width: 720px) 720px"></figure><p>Now create a new release.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.40.41.png" class="kg-image" alt="Packaging Your Rust Code" loading="lazy" width="1528" height="1418" srcset="https://skerritt.blog/content/images/size/w600/2023/06/Screenshot-2023-06-22-at-12.40.41.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/Screenshot-2023-06-22-at-12.40.41.png 1000w, https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.40.41.png 1528w" sizes="(min-width: 720px) 720px"></figure><p>Use semantic versioning to create the Tag Version. Create a new release title, and describe the release.</p><p>A good format for release descriptions is:</p><pre><code># Features

# Maintenance

# Bugs
</code></pre><p>Similar to the semantic versioning rules. I normally pull these from pull requests, or write them down as I merge commits.</p><p>Once we&#x2019;ve entered some information, click <code>Publish release</code>. We now have a published release of our app!</p><p>Our code is now in <code>.tar.gz</code> format if we look on the releases page again. GitHub does it for us!</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.41.04.png" class="kg-image" alt="Packaging Your Rust Code" loading="lazy" width="1984" height="596" srcset="https://skerritt.blog/content/images/size/w600/2023/06/Screenshot-2023-06-22-at-12.41.04.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/Screenshot-2023-06-22-at-12.41.04.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/06/Screenshot-2023-06-22-at-12.41.04.png 1600w, https://skerritt.blog/content/images/2023/06/Screenshot-2023-06-22-at-12.41.04.png 1984w" sizes="(min-width: 720px) 720px"></figure><p>Right click <strong>Source code (tar.gz)</strong> and click on &#x201C;get link&#x201D;. Now we have the link to our <code>tar.gz</code> folder.</p><p>Go into a terminal, and type:</p><pre><code>wget &lt;link&gt;
</code></pre><p>where <code>&lt;link&gt;</code> is replaced by the link you just copied.</p><p>We need the SHA256 Hash of the archive, so let&#x2019;s calculate it:</p><pre><code>shasum -a 256 rustscan.tar.gz
</code></pre><p>Where <code>rustscan.tar.gz</code> is the file you just downloaded with wget.</p><div class="kg-card kg-callout-card kg-callout-card-green"><div class="kg-callout-emoji">&#x1F42C;</div><div class="kg-callout-text">Note down the shasum, this is an important step for later. Also note down the link we used to download it.</div></div><h3 id="the-github-repository">The GitHub Repository</h3><p>Homebrew requires a separate GitHub repository for your project. Or you can change the name of your current repository.</p><p>Homebrew calls these <a href="https://docs.brew.sh/Taps?ref=skerritt.blog">taps</a>. Taps are third-party GitHub repositories with specific names and configuration files.</p><p>Go to GitHub and create a new repository. Naming it:</p><pre><code>homebrew-&lt;project&gt;
</code></pre><p>Where is the name of your project? <strong>Note</strong> it must start with the name &#x201C;homebrew-&quot;.</p><p>In my case, it is:</p><pre><code>homebrew-rustscan
</code></pre><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/RustScan/homebrew-rustscan?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - RustScan/homebrew-rustscan: RustScan&#x2019;s HomeBrew repo</div><div class="kg-bookmark-description">RustScan&#x2019;s HomeBrew repo. Contribute to RustScan/homebrew-rustscan development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Packaging Your Rust Code"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">RustScan</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/1cbb9c39f5bf09ddf7ab7e8db3166714be27e3ca07f8a863392025c761e2213b/RustScan/homebrew-rustscan" alt="Packaging Your Rust Code"></div></a></figure><p>Now clone your new repo onto your machine:</p><pre><code>git clone homebrew-&lt;project&gt;
</code></pre><h3 id="creating-the-formula">Creating the formula</h3><p>Homebrew requires a file called a formula. This is a Ruby file that details your project along with how to install the binary. You <strong>do not</strong> need to know Ruby to create this.</p><p><code>cd</code> into our newly cloned repo, and create the following file structure:</p><pre><code>- Formula/
    - &lt;project&gt;.rb
</code></pre><p>In my case:</p><pre><code>- Formula/
    - rustscan.rb
</code></pre><p>Capitalise the folder name if it is not already.</p><p>Now copy and paste the following file into your <code>rustscan.rb</code> (or whatever your project is called).</p><pre><code># Documentation: https://docs.brew.sh/Formula-Cookbook
#                https://rubydoc.brew.sh/Formula
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
class Rustscan &lt; Formula
  desc &quot;Faster Nmap Scanning with Rust&quot; 
  homepage &quot;https://github.com/bee-san/rustscan&quot;
  url &quot;https://github.com/RustScan/RustScan/archive/1.3.tar.gz&quot;
  sha256 &quot;3bbaf188fa4014a57596c4d4f928b75bdf42c058220424ae46b94f3a36b61f81&quot;
  version &quot;1.3.0&quot;
  depends_on &quot;rust&quot; =&gt; :build

  def install
    system &quot;cargo&quot;, &quot;build&quot;, &quot;--release&quot;, &quot;--bin&quot;, &quot;rustscan&quot;
    bin.install &quot;target/release/rustscan&quot;
  end
end
</code></pre><p>Change the class name to match the name of your program:</p><pre><code>class Rustscan &lt; Formula
</code></pre><p>Then add a short description and link the homepage (in my case, the GitHub repo).</p><pre><code>  desc &quot;Faster Nmap Scanning with Rust&quot; 
  homepage &quot;https://github.com/bee-san/rustscan&quot;
</code></pre><p>Now we need to fill out the download link and the SHA-256.</p><pre><code>  url &quot;https://github.com/RustScan/RustScan/archive/1.3.tar.gz&quot;
  sha256 &quot;3bbaf188fa4014a57596c4d4f928b75bdf42c058220424ae46b94f3a36b61f81&quot;
</code></pre><p>Remember earlier when I told you to write down the link &amp; the shasum? This is exactly where you&#x2019;d place them!</p><p>Now insert your version number, the same one for the whole release:</p><pre><code>version &quot;1.3.0&quot;
</code></pre><p>Our program relies on Rust to build the binary, we note this down here:</p><pre><code>  depends_on &quot;rust&quot; =&gt; :build
</code></pre><p>The next step is to detail how to build the binary and install our program. We tell Homebrew to build the binary using <code>cargo build</code>, and then to install it with <code>bin.install</code>.</p><pre><code>  def install
    system &quot;cargo&quot;, &quot;build&quot;, &quot;--release&quot;, &quot;--bin&quot;, &quot;rustscan&quot;
    bin.install &quot;target/release/rustscan&quot;
  end
</code></pre><p>And just like that, we&#x2019;ve made the formula file.</p><p>Upload this to your <code>homebrew-&lt;project&gt;</code> repository like so:</p><pre><code>git add .
git commit -m &apos;First release&apos;
git push
</code></pre><h3 id="installing-the-package">Installing the Package</h3><p>Let&#x2019;s install the package to double check everything went well.</p><pre><code>brew tap bee-san/rustscan 
brew install rustscan
</code></pre><p>Where <code>bee-san/rustscan</code> is your GitHub username combined with the project&#x2019;s name.</p><p>My username is bee-san, and the project is called rustscan.</p><p>I created a one-command install for my users. which is just the 2 commands combined. You may find this helpful.</p><pre><code>brew tap bee-san/rustscan &amp;&amp; brew install rustscan
</code></pre><h2 id="debian">Debian</h2><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">&#x1F47D;</div><div class="kg-callout-text">You can also use <a href="https://github.com/axodotdev/cargo-dist?ref=skerritt.blog">Cargo Dist</a> instead of this Docker image</div></div><p>The easiest way to create Debian binaries is to use the crate <code>cargo-deb</code>. <a href="https://crates.io/crates/cargo-deb?ref=skerritt.blog">Cargo-deb</a> is installed</p><pre><code>cargo install cargo-deb
</code></pre><p>Once it is installed, run the command:</p><pre><code>cargo-deb
</code></pre><p>And we now have a <code>.deb</code> file for our project on our system architecture.</p><p>But what if we wanted to package for other architectures?</p><p>Luckily I&#x2019;ve created a (albeit badly made) Docker script to package for other architectures.</p><p>The script packages the project for:</p><ul><li>Amd64</li><li>Arm64</li><li>i386</li></ul><p>It requires some editing (as it was made for RustScan), but once done it will automatically package your script for you.</p><p>Create a separate folder in your main project&#x2019;s repo, such as <code>rustscan-debbuilder</code>.</p><p>Then place these 3 files in there:</p><p><strong>entrypoint.sh</strong></p><pre><code>#!/bin/bash

cd /RustScan
git pull --force

#amd64
cargo deb

#arm64
rustup target add arm-unknown-linux-gnueabihf
cargo deb --target=arm-unknown-linux-gnueabihf

#i386
rustup target add i686-unknown-linux-gnu
cargo deb --target=i686-unknown-linux-gnu

find target/ -name \*.deb -exec cp {} /debs \;
</code></pre><p>Change <code>cd /RustScan</code> to your project name.</p><p><strong>run.sh</strong></p><pre><code>#!/bin/bash
docker build -t rustscan-builder . || exit

# This creates a volume which binds your currentdirectory/debs to 
# the location where the deb files get spat out in the container.
# You don&apos;t need to worry about it. Just chmod +x run.sh &amp;&amp; ./run.sh and
# you&apos;ll get yer .deb file in a few minutes. It runs faster after you&apos;ve used it the first time.
docker run -v &quot;$(pwd)/debs:/debs&quot; rustscan-builder
</code></pre><p><strong>Dockerfile</strong></p><pre><code>FROM rust:latest

RUN git clone https://github.com/bee-san/RustScan
WORKDIR &quot;/RustScan&quot;
RUN git pull --force
RUN cargo install cargo-deb

RUN apt update -y &amp;&amp; apt upgrade -y
RUN apt install libc6-dev-i386 -y
RUN git clone --depth=1 https://github.com/raspberrypi/tools /raspberrypi-tools
ENV PATH=/raspberrypi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/:$PATH
ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
RUN mkdir /root/.cargo
RUN echo &quot;[target.arm-unknown-linux-gnueabihf]&quot; &gt;&gt; /root/.cargo/config
RUN echo &quot;strip = { path = \&quot;arm-linux-gnueabihf-strip\&quot; }&quot; &gt;&gt; /root/.cargo/config
RUN echo &quot;objcopy = { path = \&quot;arm-linux-gnueabihf-objcopy\&quot; }&quot; &gt;&gt; /root/.cargo/config

COPY ./entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT [&quot;/entrypoint.sh&quot;]
</code></pre><p>Change <code>RUN git clone [https://github.com/bee-sa/RustScan](https://github.com/bee-san/RustScan)</code> to the git repository link of your choice.</p><p>Change <code>WORKDIR &quot;/RustScan</code> to your project&#x2019;s name.</p><p>The directory should look like:</p><pre><code>- rustscan-debbuilder /
    Dockerfile
    run.sh
    entrypoint.sh
</code></pre><p>Now to run this builder:</p><pre><code>cd rustscan-debbuilder
chmod +x run.sh
./run.sh
</code></pre><p>And it will build 3 Debian binaries for you.</p><h3 id="installation-of-deb-files">Installation of .deb files</h3><p>To install <code>.deb</code> files, you can run <code>dpkg -i</code> on the file, or you can double-click the file (on some systems).</p><h1 id="arch">Arch</h1><p>The easiest way to distribute for AUR is to use the Cargo package <code>cargo-aur</code>. </p><p>The PKGBUILD file is similar to <code>cargo.toml</code>, or our Homebrew file.</p><p>Let&#x2019;s open up the file and edit some fields (if we want to).</p><pre><code># Maintainer: Bee &lt;bee@fake.com&gt;
pkgname=rustscan
pkgver=1.4.1
pkgrel=1
pkgdesc=&quot;Faster Nmap Scanning with Rust&quot;
url=&quot;https://github.com/bee-san/rustscan&quot;
license=(&quot;MIT&quot;)
arch=(&quot;x86_64&quot;)
provides=(&quot;rustscan&quot;)
options=(&quot;strip&quot;)
source=(&quot;https://github.com/bee-san/rustscan/releases/download/v$pkgver/rustscan-$pkgver-x86_64.tar.gz&quot;)
sha256sums=(&quot;7bed834f5df925b720316341150df74ac2533cc968de54bb1164c95ea9b65db8&quot;)

package() {
    install -Dm755 rustscan -t &quot;$pkgdir/usr/bin/&quot;
}
</code></pre><p>The <code>pkgname</code> is the name of the package. Please see the <a href="https://wiki.archlinux.org/index.php/Arch_package_guidelines?ref=skerritt.blog#Package_naming">Arch wiki</a> for guidance on naming conventions.</p><p><code>pkgver</code> is the semantic version of our package. This is automatically taken from <code>cargo.toml</code>.</p><p><code>pkgrel</code> means &#x201C;this package has updated&#x201D;. Nothing more to it, but the <a href="https://wiki.archlinux.org/index.php/PKGBUILD?ref=skerritt.blog#pkgrel">Arch Wiki explains</a> this concept in more detail.</p><p><code>pkgdesc</code> is the description of our package.</p><p><code>arch</code> is the architecture our package will compile on.</p><p><code>provides</code> is an array of packages that the software provides the features are. Packages providing the same item can be installed side-by-side unless one of them has a conflicts array.</p><p><code>options</code> per the <a href="https://wiki.archlinux.org/index.php/PKGBUILD?ref=skerritt.blog#pkgrel">Arch Wiki</a>:</p><blockquote>This array allows overriding some of the default behavior of <em>makepkg</em>, defined in <code>/etc/makepkg.conf</code>. To set an option, include the name in the array. To disable an option, place an <strong><code>!</code></strong> before it.</blockquote><p>Personally, I don&#x2019;t know why this is needed. But it&#x2019;s an automated generation, so we can&#x2019;t complain too much.</p><p><code>source</code> is the location of the release on GitHub, and <code>sha256sums</code> are the checksums of the package.</p><p>Finally, <code>package()</code> shows Arch how to install our package.</p><h2 id="uploading-this-package-to-the-aur">Uploading this package to the AUR</h2><ol><li><code>cargo aur</code> built a tarball <code>.tar</code> file. Create a new <code>release on GitHub and attach the </code>.tar` file that was just created.</li><li> Create an account on the AUR <a href="https://aur.archlinux.org/?ref=skerritt.blog">https://aur.archlinux.org/</a></li><li>Upload your SSH public key to your account.</li></ol><p>Check for SSH keys with:</p><pre><code>ls -al ~/.ssh
</code></pre><p>And you&#x2019;re likely looking for a file like *<code>id_rsa.pub</code>. *</p><p>If this doesn&#x2019;t exist, generate a new SSH key with:</p><pre><code>$ ssh-keygen -t rsa -b 4096 -C &quot;your_email@example.com&quot;
</code></pre><p>And follow the on-screen prompts. Or follow this <a href="https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent?ref=skerritt.blog">guide</a> if you are still confused.</p><p>Next, go to your account page on the AUR and upload your public SSH key.</p><ol><li>In a new directory, git clone your repo on the AUR.</li></ol><p>This is kind of confusing. But say the package name is <code>rustscan</code> (confirm there is no other package on the AUR using your projects name by <a href="https://aur.archlinux.org/?ref=skerritt.blog">searching here</a>).</p><pre><code>git clone ssh://aur@aur.archlinux.org/rustscan.git
</code></pre><p>I normally clone this in a folder format like:</p><pre><code>- rustscan /
    - rustscan / # the rust package
    - rustscan / # the package we have git cloned
    - homebrew-rustscan /
</code></pre><p>Make sure to change the name of the package <code>rustscan</code> to the name you want.</p><ol><li>Copy the PKGBUILD you built in stage 1 into the new Git repo.</li><li>Run <code>makepkg --printsrcinfo &gt; .SRCINFO</code> in the repo.</li></ol><p>Your directory should now look like:</p><ul><li>rustscan /</li><li>rustscan / # the rust package</li><li>rustscan / # the package we have git cloned</li><li>PKGBUILD</li><li>.SRCINFO</li><li>homebrew-rustscan /</li></ul><p>Now push these:</p><p>git add . git commit -m &#x2018;initial release&#x2019; git push</p><p>And Ta-Da! We now have an Arch Linux AUR package!</p><p>Eventually, you may want to clean up the default Rust AUR package for whatever reason. This is the one RustScan uses. Feel free to copy &amp; change it however you wish:</p><pre><code># Maintainer: Hao Last_name_emited_for_privacy &lt;email_emited_for_privacy&gt;

pkgname=rustscan
_pkgname=RustScan
pkgver=1.6.0
pkgrel=1
pkgdesc=&quot;Faster Nmap Scanning with Rust&quot;
arch=(&quot;x86_64&quot; &quot;i686&quot;)
url=&quot;https://github.com/rustscan/RustScan&quot;
license=(&quot;GPL3&quot;)
provides=(&apos;rustscan&apos;)
conflicts=(&apos;rustscan&apos;)
depends=(&quot;nmap&quot;)
makedepends=(&quot;cargo&quot;)
source=(&quot;${pkgname}-${pkgver}.tar.gz::${url}/archive/${pkgver}.tar.gz&quot;)
sha256sums=(&apos;a4ebe4b8eda88dd10d52d961578c95b5427cc34b3bf41e5df729a37122c68965&apos;)

build() {
  cd ${_pkgname}-${pkgver}
  cargo build --release --locked --all-features --target-dir=target
}

package() {
  cd ${_pkgname}-${pkgver}
  install -Dm755 target/release/${pkgname} ${pkgdir}/usr/bin/${pkgname}
}
</code></pre><p>Note: someone else made this for RustScan.</p>]]></content:encoded></item><item><title><![CDATA[Divide and Conquer Algorithms with Python Examples]]></title><description><![CDATA[<p>Often I&#x2019;ll hear about how you can optimise a for loop to be faster or how switch statements are faster than if statements. Most computers have over 1 core, with the ability to support multiple threads. Before worrying about optimising for loops or if statements try to attack</p>]]></description><link>https://skerritt.blog/divide-and-conquer-algorithms/</link><guid isPermaLink="false">62d59dc1b9b846003d96ded4</guid><category><![CDATA[programming]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Thu, 22 Jun 2023 07:07:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1658050206983-079c752b5752?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDMwfHx8fHx8Mnx8MTY1ODE2NjcyMQ&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1658050206983-079c752b5752?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDMwfHx8fHx8Mnx8MTY1ODE2NjcyMQ&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Divide and Conquer Algorithms with Python Examples"><p>Often I&#x2019;ll hear about how you can optimise a for loop to be faster or how switch statements are faster than if statements. Most computers have over 1 core, with the ability to support multiple threads. Before worrying about optimising for loops or if statements try to attack your problem from a different angle.</p><p>Divide and Conquer is one way to attack a problem from a different angle. Don&#x2019;t worry if you have <strong>zero</strong> experience or knowledge on the topic. This article is designed to be read by someone with very little programming knowledge.</p><p>I will explain this using 3 examples. The first will be a simple explanation. The second will be some code. The final will get into the mathematical core of divide and conquer techniques. (Don&#x2019;t worry, I hate maths too).</p><hr><h2 id="what-is-divide-and-conquer-%F0%9F%8C%8E">What Is Divide and Conquer? &#x1F30E;</h2><p>Divide and conquer is where you divide a large problem up into many smaller, much easier-to-solve problems. The rather small example below illustrates this.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-151.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="500" height="280"></figure><p>We take the equation &#x201C;3 + 6 + 2 + 4&#x201D; and cut it down into the smallest set of equations, which is [3 + 6, 2 + 4]. It could also be [2 + 3, 4 + 6]. The order doesn&#x2019;t matter, as long as we turn this one long equation into many smaller equations.</p><p>Let&#x2019;s say we have 8 numbers:</p><p>$$4+6+3+2+8+7+5+1$$</p><p>We want to add them all together. We first divide the problem into 8 equal sub-problems. We do this by breaking the addition up into individual numbers.</p><p>$$4 + 6 \; 3 + 2 \; 8 + 7 \; 5 + 1$$</p><p>We then add 2 numbers at a time.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-152.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="540" height="240"></figure><p>Then 4 numbers into 8 numbers which is our resultant.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-153.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="680" height="440" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-153.png 600w, https://skerritt.blog/content/images/2023/06/image-153.png 680w"></figure><p>Why do we break it down to individual numbers at stage 1? Why don&#x2019;t we just start from stage 2? Because while this list of numbers is even if the list was odd you would need to break it down to individual numbers to better handle it.</p><p>A divide and conquer algorithm tries to break a problem down into as many little chunks as possible since it is easier to solve with little chunks. It does this with recursion.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-154.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="924" height="605" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-154.png 600w, https://skerritt.blog/content/images/2023/06/image-154.png 924w" sizes="(min-width: 720px) 720px"></figure><hr><h2 id="recursion">Recursion</h2><p>Before we get into the rest of the article, let&#x2019;s learn about recursion first.</p><p><strong>Recursion is when a function calls itself.</strong> It&#x2019;s a hard concept to understand if you&#x2019;ve never heard of it before. <a href="https://www.google.com/search?hl=en&amp;q=recursion&amp;ref=skerritt.blog">This page provides a good explanation</a>.</p><p>Matryoshka dolls are these cute little things:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-155.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="730" height="365" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-155.png 600w, https://skerritt.blog/content/images/2023/06/image-155.png 730w" sizes="(min-width: 720px) 720px"></figure><p>We open up the bigger one and inside is a slightly smaller one. Inside that one is another slightly small doll. Let&#x2019;s say, inside the last doll is a key. But we do not know how many dolls there are. How do we write a function that opens up the dolls until we find a key?</p><p>We could use a while loop, but recursion is preferred here.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-156.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="331" height="171"></figure><p>To program this, we can write:</p><pre><code class="language-python">def getKey(doll):
    item = doll.open()
    if item == key:
        return key
    else:
        return getKey(item)
getKey(doll)
</code></pre><p>The function repeatedly calls itself until it finds a key, at which point it stops. The finding key point is called a <em>break case</em> or <em>exit condition</em>.</p><p>We always add a break case to a recursive function. If we didn&#x2019;t, it&#x2019;d just be an infinite loop! Never-ending.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">&#x1F400;</div><div class="kg-callout-text">A great example of a never ending statement could be TikTok sounds, where the sound repeats on and on and makes you crazy. Crazy? I was crazy once. They locked me in a room. A rubber room. A rubber room with rats. The rats made me crazy. <a href="https://www.youtube.com/watch?v=Ukf2RyAVvpU&amp;ref=skerritt.blog">Crazy</a>?</div></div><p>Computer scientists <strong>love</strong> recursion. Because it&#x2019;s so hard for normal people to understand, we have a schadenfreude sensation watching people struggle. Haha just kidding!</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F913;</div><div class="kg-callout-text">After working in the industry I can now confirm one of the methods of job security is to deliberately make your code much harder to read so other people struggle with it and they can&apos;t fire you. I haven&apos;t done this, but I have seen people that have....</div></div><p>We love recursion because it&#x2019;s used in maths <strong>all the time</strong>. Computer scientists are mathematicians first, and coders second. Anything that brings code closer to real-life mathematics is good.</p><p>Not just because some people love maths, but because it makes it easier to implement. Need to calculate the Fibonacci numbers? The maths equation for this is:</p><p>$$F(n) = \begin{cases} n, \text{If n = 0 or 1} \\ F(n - 1) + F(n - 2), \ \text{if n &gt; 1} \end{cases}$$</p><p>A natural recurrence in our formula! Instead of translating it into loops, we can just calculate it:</p><pre><code class="language-python">def F(n):
    if n == 0 or n == 1:
        return n
    else:
        return F(n-1)+F(n-2)
</code></pre><p>This is one of the reasons why <a href="https://skerritt.blog/learn-functional-python-in-10-minutes/">functional programming is so cool.</a></p><p>Also, as you&#x2019;ll see throughout this article, recursion reads so much nicer than loops. And hey, maybe you can feel a little happier when your coworker doesn&#x2019;t understand recursion but you do ;)</p><hr><h2 id="back-to-divide-conquer">Back to Divide &amp; Conquer</h2><p>The technique, as defined in the famous <a href="https://www.amazon.co.uk/Introduction-Algorithms-Thomas-H-Cormen/dp/0262033844/ref=as_li_ss_tl?keywords=Introduction+to+Algorithms&amp;qid=1551954553&amp;s=gateway&amp;sr=8-1&amp;linkCode=ll1&amp;tag=brandon0fe-21&amp;linkId=72a63dce0d8099988383cc3767340d40&amp;language=en_GB&amp;ref=skerritt.blog">Introduction to Algorithms</a> by Cormen, Leiserson, Rivest, and Stein, is:</p><ol><li>Divide</li></ol><p>If the problem is small, then solve it directly. Otherwise, divide the problem into smaller subsets of the same problem.</p><p>2. Conquer</p><p>Conquer the smaller problems by solving them recursively. If the sub-problems are small enough, recursion is not needed and you can solve them directly.</p><p>3. Combine</p><p>Take the solutions to the sub-problems and merge them into a solution to the original problem.</p><p>Let&#x2019;s look at another example, calculating the factorial of a number.</p><pre><code class="language-python">n = 6

def recur_factorial(n):
    if n == 1:
        return n
    else:
        return n * recur_factorial(n-1)

print(recur_factorial(n))
</code></pre><p>With the code from above, some important things to note. The Divide part is also the recursion part. We divide the problem up at <code>return n * recur_factorial(n-1)</code>.</p><p>The <code>recur_factorial(n-1)</code> part is where we divide the problem up.</p><p>The conquering part is the recursion part too, but also the if statement. If the problem is small enough, we solve it directly (by returning n). Else, we perform <code>return n * recur_factorial(n-1)</code>.</p><p>Combine. We do this with the multiplication symbol. Eventually, we return the factorial of the number. If we didn&#x2019;t have the symbol there, and it was <code>return recur_factorial(n-1)</code> it wouldn&#x2019;t combine and it wouldn&#x2019;t output anything similar to the factorial. (It&#x2019;ll output 1, for those interested).</p><p>We&#x2019;ll explore how to divide and conquer works in some famous algorithms, Merge Sort and the solution to the Towers of Hanoi.</p><h3 id="one-last-time">One last time</h3><ol><li><strong>Divide / Break</strong>. Break the problem into smaller sub-problems.</li><li><strong>Conquer / Solve</strong>. Solves all the sub-problems.</li><li><strong>Merge / Combine</strong>. Merges all the sub-solutions into one solution.</li></ol><h1 id="merge-sort-%F0%9F%A4%96">Merge Sort &#x1F916;</h1><p>Merge Sort is a sorting algorithm. The algorithm works as follows:</p><ul><li>Divide the sequence of n numbers into 2 halves</li><li>Recursively sort the two halves</li><li>Merge the two sorted halves into a single sorted sequence</li></ul><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-157.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="1480" height="780" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-157.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-157.png 1000w, https://skerritt.blog/content/images/2023/06/image-157.png 1480w" sizes="(min-width: 720px) 720px"></figure><p>In this image, we break down the 8 numbers into separate digits. Just like we did earlier. Once we&#x2019;ve done this, we can begin the sorting process.</p><p>It compares 51 and 13. Since 13 is smaller, it puts it on the left-hand side. It does this for (10, 64), (34, 5), (32, 21).</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-158.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="1480" height="320" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-158.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-158.png 1000w, https://skerritt.blog/content/images/2023/06/image-158.png 1480w" sizes="(min-width: 720px) 720px"></figure><p>It then merges (13, 51) with (10, 64). It knows that 13 is the smallest in the first list, and 10 is the smallest in the right list. 10 is smaller than 13, therefore we don&#x2019;t need to compare 13 to 64. We&#x2019;re comparing &amp; merging two **sorted **lists.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-159.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="1480" height="660" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-159.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-159.png 1000w, https://skerritt.blog/content/images/2023/06/image-159.png 1480w" sizes="(min-width: 720px) 720px"></figure><p>In recursion, we use the term <em>base case</em> to refer to the absolute smallest value we can deal with. With Merge Sort, the base case is 1. That means we split the list up until we get sub-lists of length 1. That&#x2019;s also why we go down all the way to 1 and not 2. If the base case was 2, we would stop at the 2 numbers.</p><p>If the length of the list (n) is larger than 1, then we divide the list and each sub-list by 2 until we get sub-lists of size 1. If n = 1, the list is already sorted so we do nothing.</p><p>Merge Sort is an example of a divide-and-conquer algorithm. Let&#x2019;s look at one more algorithm to understand how divide and conquer works.</p><hr><h2 id="towers-of-hanoi-%F0%9F%97%BC">Towers of Hanoi &#x1F5FC;</h2><p>The Towers of Hanoi is a mathematical problem which compromises 3 pegs and 3 discs. This problem is mostly used to teach recursion, but it has some <a href="https://www.ibm.com/developerworks/community/blogs/jfp/entry/towers_of_hanoi_at_large1?lang=en&amp;ref=skerritt.blog">real-world uses.</a> The number of pegs &amp; discs can change.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-160.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="1200" height="538" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-160.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-160.png 1000w, https://skerritt.blog/content/images/2023/06/image-160.png 1200w" sizes="(min-width: 720px) 720px"></figure><p>Each disc is a different size. We want to move all discs to peg C so that the largest is on the bottom, the second largest on top of the largest, third largest (smallest) on top of all of them. There are some rules to this game:</p><ol><li>We can only move 1 disc at a time.</li><li>A disc cannot be placed on top of other discs that are smaller than it.</li></ol><p>We want to use the smallest number of moves possible. If we have 1 disc, we only need to move it once. For 2 discs, we need to move it 3 times.</p><p>The number of moves is a power of 2 minus 1. Say we have 4 discs, we calculate the minimum number of moves as \(2^4 = 16 - 1 = 15\).</p><p>To solve the above example we want to store the smallest disc in a buffer peg (1 move). See below for a gif on solving Tower of Hanoi with 3 pegs and 3 discs.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/hanoi.gif" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="1200" height="538" srcset="https://skerritt.blog/content/images/size/w600/2023/06/hanoi.gif 600w, https://skerritt.blog/content/images/size/w1000/2023/06/hanoi.gif 1000w, https://skerritt.blog/content/images/2023/06/hanoi.gif 1200w" sizes="(min-width: 720px) 720px"></figure><p>Notice how we need to have a buffer to store the discs.</p><p>We can generalise this problem. If we have n discs: move n-1 from A to B recursively, move largest from A to C, and move n-1 from B to C recursively.</p><p>If there is an even number of pieces the first move is always into the middle. If it is odd the first move is always to the other end.</p><p>Let&#x2019;s code the algorithm for ToH, in pseudocode.</p><pre><code class="language-python">function MoveTower(disk, source, dest, spare):
    if disk == 0, then:
        move disk from source to dest
</code></pre><p>We start with a base case, <code>disk == 0</code>. <code>source</code> is the peg you&#x2019;re starting at. <code>dest</code> is the final destination peg. <code>spare</code> is the spare peg.</p><pre><code class="language-python">FUNCTION MoveTower(disk, source, dest, spare):
IF disk == 0, THEN:
    move disk from source to dest
ELSE:
    MoveTower(disk - 1, source, spare, dest)   // Step 1
    move disk from source to dest              // Step 2
    MoveTower(disk - 1, spare, dest, source)   // Step 3
END IF
</code></pre><p>Notice that with step 1 we switch <code>dest</code> and <code>source</code>. We do not do this for step 3.</p><p>With recursion, we know 2 things:</p><ol><li>It always has a base case (if it doesn&#x2019;t, how does the algorithm know to end?)</li><li>The function calls itself.</li></ol><p>The algorithm gets a little confusing with steps 1 and 3. They both call the same function. This is where multi-threading comes in. You can run steps 1 and 3 on different threads - at the same time.</p><p>Since 2 is more than 1, we move it down one more level again. So far you&#x2019;ve seen what the divide and conquer technique is. You should understand how it works and what code looks like. Next, let&#x2019;s learn how to define an algorithm to a problem using divide and conquer. This part is the most important. Once you know this, it&#x2019;ll be easier to create divide and conquer algorithms.</p><hr><h2 id="how-to-identify-divide-and-conquer-problems">How to identify Divide and Conquer problems</h2><p>When we have a problem that looks similar to a famous divide &amp; conquer algorithm (such as merge sort), it will be useful.</p><p>Most of the time, the algorithms we design will be most similar to merge sort. If we have an algorithm that takes a list and does something with each element of the list, it might be able to use divide &amp; conquer.</p><p>For example, working out the largest item of a list. Given a list of words, how many times does the letter &#x201C;e&#x201D; appear?</p><p>If we have an <a href="https://skerritt.blog/big-o/">algorithm that is slow</a> and we would like to speed it up, one of our first options is divide and conquer.</p><p>There aren&#x2019;t any obvious tell-tale signs other than &#x201C;similar to a famous example&#x201D;. But as we&#x2019;ll see in the next section, we can check if it is solvable using divide &amp; conquer.</p><hr><h2 id="how-to-solve-problems-using-divide-and-conquer">How to solve problems using divide and conquer</h2><p>Now we know how divide and conquer algorithms work, we can build up our own solution. In this example, we&#x2019;ll walk through how to build a solution to the Fibonacci numbers.</p><h3 id="fibonacci-numbers-%F0%9F%90%B0">Fibonacci Numbers &#x1F430;</h3><p>We can find Fibonacci numbers in nature. The way <a href="http://www.oxfordmathcenter.com/drupal7/node/487?ref=skerritt.blog">rabbits produce </a>is in the style of the Fibonacci numbers. You have 2 rabbits that make 3, 3 rabbits make 5, 5 rabbits make 9 and so on.</p><p>The numbers start at 0 and the next number is the current number + the previous number. But by mathematical definition, the first 2 numbers are 0 and 1.</p><p>Let&#x2019;s say we want to find the 5 Fibonacci numbers. We can do this:</p><pre><code class="language-python"># [0, 1]
0 + 1 = 1 # 3rd fib number
# [0, 1, 1]
1 + 1 = 2 # 4th fib number
# [0, 1, 1, 2]
2 + 1 = 3 # 5th fib number
# [0, 1, 1, 2, 3]
</code></pre><p>Now the first thing when designing a divide and conquer algorithm is to design the recurrence. The recurrence always starts with a base case.</p><p>We can describe this relation using a recursion. A recurrence is an equation which defines a function in terms of its smaller inputs. Recurrence and recursion sound similar and are similar.</p><p>As we saw, our base case is the 2 numbers at the start.</p><pre><code class="language-python">def f(n):
    if n == 0 or n == 1:
        return n
</code></pre><p>To calculate the 4th Fibonacci number, we do (4 - 1) + (4 - 2). This means (last number in the sequence) + (the number before the last). &#xA0;Or in other words:</p><blockquote>The next number is the current number + the previous number.</blockquote><p>If our number is not 0 or 1, we want to add the last 2 Fibonacci numbers together.</p><p>Let&#x2019;s take a look at our table quickly:</p><pre><code class="language-python"># [0, 1]
0 + 1 = 1
# [0, 1, 1]
1 + 1 = 2 
# [0, 1, 1, 2]
2 + 1 = 3 
# [0, 1, 1, 2, 3]
2 + 3 = 5
# [0, 1, 1, 2, 3, 5]
</code></pre><p>But what if we don&#x2019;t have this list stored? How do we calculate the 6th number without creating a list at all? Well we know that the 6th number is the 5th number + the 4th number. Okay, what are those? The 5th number is the 4th number + the 3rd number. The 4th number is the 3rd number + the second number.</p><p>We know that the second number is always 1, as we&#x2019;ve reached a base case.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-161.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="1740" height="983" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-161.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-161.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/06/image-161.png 1600w, https://skerritt.blog/content/images/2023/06/image-161.png 1740w" sizes="(min-width: 720px) 720px"></figure><p>Eventually, we break it down to the base cases. Okay, so we know our code calls itself to calculate the Fibonacci numbers of the previous ones:</p><pre><code class="language-python">def f(n):
    if n == 0 or n == 1:
        return n
    else:
        f(n-1) f(n-2)
</code></pre><p>Okay, how do we merge the Fibonacci numbers at the end? As we saw, it is the last number **added **to the current number.</p><pre><code class="language-python">def f(n):
    if n == 0 or n == 1:
        return n
    else:
        f(n-1) + f(n-2)
</code></pre><p>Now we&#x2019;ve seen this, let&#x2019;s turn it into recursion using a recurrence. Luckily for us, it&#x2019;s incredibly easy to go from a recurrence to code or from code to a recurrence, as they are both recurrences!</p><p>$$ F(n) = \begin{cases} n, \text{If n = 0 or 1} \\ &#xA0;F(n - 1) + F(n - 2), \ \text{if n &gt; 1} \end{cases} $$</p><p>We often calculate the result of a recurrence using an <strong>execution tree.</strong> We saw this earlier when exploring how to build it in code. For F(6) this looks like:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-162.png" class="kg-image" alt="Divide and Conquer Algorithms with Python Examples" loading="lazy" width="1740" height="983" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-162.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-162.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/06/image-162.png 1600w, https://skerritt.blog/content/images/2023/06/image-162.png 1740w" sizes="(min-width: 720px) 720px"></figure><p>n is 4, and n is larger than 0 or 1. So we do f(n-1) + f(n-2). We ignore the addition for now. This results in 2 new nodes, 3 and 2. 3 is larger than 0 or 1 so we do the same. Same for 2. We do this until we get a bunch of nodes which are either 0 or 1.</p><p>We then add all the nodes together.</p><p>$$0 + 1 + 1 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 0 + 1 = 8$$</p><h2 id="when-should-i-use-divide-conquer-%F0%9F%8E%87">When Should I Use Divide &amp; Conquer? &#x1F387;</h2><p>When we have a problem that looks similar to a famous divide &amp; conquer algorithm (such as merge sort), it will be useful.</p><p>Most of the time, the algorithms we design will be most similar to merge sort. If we have an algorithm that takes a list and does something with each element of the list, it might be able to use divide &amp; conquer.</p><p>For example, working out the largest item of a list. Given a list of words, how many times does the letter &#x201C;e&#x201D; appear?</p><hr><h2 id="big-o-notation-of-divide-conquer-algorithms">Big O Notation of Divide &amp; Conquer Algorithms</h2><p>Normally if our algorithm follows a famous divide &amp; conquer (algorithm) we can infer our big o from that.</p><p><a href="https://skerritt.blog/big-o/#%F0%9F%A7%AE-how-to-calculate-big-o-notation-for-our-own-algorithms-with-examples">This is no different from calculating the big o notation of our own algorithms.</a></p><hr><h2 id="divide-conquer-vs-dynamic-programming-vs-greedy">Divide &amp; Conquer vs Dynamic Programming vs Greedy</h2><!--kg-card-begin: html-->
<table>
    <thead>
        <tr>
            <th colspan="3">Greedy vs Divide &amp; Conquer vs Dynamic Programming</th>
        </tr>
    </thead>
    <tbody>
        <tr>
          <td><strong>Greedy</strong></td>
          <td><strong>Divide &amp; Conquer</strong></td>
          <td><strong>Dynamic Programming</strong></td>
        </tr>
      <tr>
        <td>Optimises by making the best choice at the moment</td>
        <td>Optimises by breaking down a subproblem into simpler versions of itself and using multi-threading &amp; recursion to solve</td>
        <td>Same as Divide and Conquer, but optimises by caching the answers to each subproblem as not to repeat the calculation twice.</td>
      </tr>
      <tr>
        <td>Doesn&apos;t always find the optimal solution, but is very fast</td>
        <td>Always finds the optimal solution, but is slower than Greedy</td>
        <td>Always finds the optimal solution, but could be pointless on small datasets.</td>
      </tr>
      <tr>
        <td>Requires almost no memory</td>
        <td>Requires some memory to remember recursive calls</td>
        <td>Requires a lot of memory for memoisation / tabulation</td>
    </tr></tbody>
</table><!--kg-card-end: html--><hr><h2 id="conclusion-%F0%9F%93%95">Conclusion &#x1F4D5;</h2><p>Once you&#x2019;ve identified how to break a problem down into many smaller pieces, you can use concurrent programming to execute these pieces at the same time (on different <a href="https://www.wikiwand.com/en/Thread_(computing)?ref=skerritt.blog">threads</a>) speeding up the whole algorithm.</p><p>Divide-and-conquer algorithms are one of the fastest and perhaps easiest ways to increase the speed of an algorithm and are useful in everyday programming. Here are the most important topics we covered in this article:</p><ul><li>What is divide and conquer?</li><li>Recursion</li><li>Merge sort</li><li>Towers of Hanoi</li><li>Coding a divide and conquer algorithm</li><li>Recurrences</li><li>Fibonacci numbers</li></ul><p>The next step is to explore multi-threading. Choose your programming language of choice and Google, as an example, &#x201C;Python multi-threading&#x201D;. Figure out how it works and see if you can attack any problems in your own code from this new angle.</p><p>You can also learn about how to solve recurrences (finding out the asymptotic running time of a recurrence), which is the next article I&#x2019;m going to write. If you don&#x2019;t want to miss it, or you liked this article do consider subscribing to my email list &#x1F601;</p>]]></content:encoded></item><item><title><![CDATA[Ripgrep cheatsheet]]></title><description><![CDATA[<p>I use RipGrep all the time, but sometimes when I want to do something I have to search the internet to find out.</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/BurntSushi/ripgrep?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - BurntSushi/ripgrep: ripgrep recursively searches directories for a regex pattern while respecting your gitignore</div><div class="kg-bookmark-description">ripgrep recursively searches directories for a regex pattern while respecting your</div></div></a></figure>]]></description><link>https://skerritt.blog/ripgrep-cheatsheet/</link><guid isPermaLink="false">6490362cd95dc60001b86182</guid><category><![CDATA[programming]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Wed, 21 Jun 2023 15:33:37 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1685171755238-0b1c05b0fd84?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8YWxsfDd8fHx8fHwyfHwxNjg3MzU5ODI2fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1685171755238-0b1c05b0fd84?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8YWxsfDd8fHx8fHwyfHwxNjg3MzU5ODI2fA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Ripgrep cheatsheet"><p>I use RipGrep all the time, but sometimes when I want to do something I have to search the internet to find out.</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/BurntSushi/ripgrep?ref=skerritt.blog"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - BurntSushi/ripgrep: ripgrep recursively searches directories for a regex pattern while respecting your gitignore</div><div class="kg-bookmark-description">ripgrep recursively searches directories for a regex pattern while respecting your gitignore - GitHub - BurntSushi/ripgrep: ripgrep recursively searches directories for a regex pattern while respec&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Ripgrep cheatsheet"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">BurntSushi</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/78fd1417b6c54db3ade12b0f5832ff65e0e43ae82a1112b269f8556b4ae52583/BurntSushi/ripgrep" alt="Ripgrep cheatsheet"></div></a></figure>
<p>Well, no more! I made this cheatsheet for myself. Maybe it&apos;ll help you.</p>
<h1 id="ripgrep-search-for-specific-file-types">Ripgrep search for specific file types</h1>
<h2 id="problem"><strong>Problem</strong></h2>
<p>You want to find out where the <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html?ref=skerritt.blog">AWS ARN</a> <code>123456789012</code> is used. You have a mono-repo with many file types in it. You&apos;re only interested in Terraform files.</p>
<h2 id="solution-globbing-for-file-types"><strong>Solution globbing for file types</strong></h2>
<pre><code>rg &apos;123456789012&apos; -g &apos;*.tf&apos;</code></pre>
<p>This globs through all files that end with <code>.tf</code> (the Terraform extension) for the ARN.</p>
<h2 id="problem-1"><strong>Problem</strong></h2>
<p>You want to search for the API endpoint &quot;localhost:4531&quot; through all Rust files.</p>
<h2 id="solution-using-ripgreps-types"><strong>Solution using Ripgrep&apos;s types</strong></h2>
<p>Ripgrep comes with a number of filetypes built in. You can do:</p>
<pre><code class="language-python">rg &quot;localhost:4531&quot; --type rust
# or more succinctly 
rg &quot;localhost:4531&quot; --trust</code></pre>
<p>You can find the full list of file types with <code>ripgrep --type-list</code>. </p>
<div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><b><strong>Pro tip</strong></b>: Do rg --type-list | rg terraform to see if your file type is supported.</div></div>
<h2 id="problem-2">Problem</h2>
<p>You want to find where the ARN is used, but want to ignore all markdown files.</p>
<h2 id="solution-using-inverse-type-selection">Solution using inverse type selection</h2>
<pre><code>rg &apos;123456789012&apos; --type-not markdown</code></pre>
<h1 id="case-insensitive">Case insensitive</h1>
<figure class="kg-card kg-code-card"><pre><code>$ rg example

$ rg -i example
hello_blog
1:ExAmple</code></pre><figcaption><p><code><span>-i</span></code><span> does it.</span></p></figcaption></figure>
<h1 id="regex-support">Regex support</h1>
<p>Ripgrep supports regex search by default.</p>
<figure class="kg-card kg-code-card"><pre><code>$ rg &apos;fast\w+&apos; README.md
75:  faster than both. (N.B. It is not, strictly speaking, a &quot;drop-in&quot; replacement
119:### Is it really faster than everything else?</code></pre><figcaption><p><span>Find the word </span><code><span>fast</span></code><span> followed by some number of other letters.</span></p></figcaption></figure>
<h1 id="literal-string-no-regex">Literal string (no regex)</h1>
<p>Ripgrep by default uses regex to search. Sometimes the word we want to find contains valid regex, so this is an issue.</p>
<figure class="kg-card kg-code-card"><pre><code>$ rg &apos;hello*.&apos;
hello_blog
3:hello.*
4:hello this is a test

</code></pre><figcaption><p><span>&#x2639;&#xFE0F;</span></p></figcaption></figure>
<p>We can search literally with:</p>
<figure class="kg-card kg-code-card"><pre><code>$ rg -F &apos;hello.*&apos;
hello_blog
3:hello.*</code></pre><figcaption><p><code><span>-F</span></code><span> is the argument</span></p></figcaption></figure>
<h1 id="show-lines-around-the-found-text">Show lines around the found text</h1>
<p>Sometimes we want to search for something, and we&apos;d like context on the found text in the file.</p>
<p>To find 1 line before our matched text:</p>
<figure class="kg-card kg-code-card"><pre><code>$ rg &quot;hello&quot; -B 1
hello_blog
2-ThisIsATest
3:hello.*</code></pre><figcaption><p><code><span>-B</span></code><span> for before</span></p></figcaption></figure>
<p>To find 1 line after our matched text:</p>
<figure class="kg-card kg-code-card"><pre><code>$ rg &quot;hello&quot; -A 1
hello_blog
3:hello.*
4-Disney</code></pre><figcaption><p><code><span>-A</span></code><span> for after</span></p></figcaption></figure>
<p>To find 1 line before and after our text:</p>
<figure class="kg-card kg-code-card"><pre><code>$ rg &quot;hello&quot; -C 1
hello_blog
2-ThisIsATest
3:hello.*
4-Disney</code></pre><figcaption><p><code><span>-C</span></code><span> for a combination of A and B</span></p></figcaption></figure>
<h1 id="get-statistics-of-a-search">Get statistics of a search</h1>
<p>I use this to work out how much work it would be to go through my search.</p>
<p>So searching &quot;crypto&quot; would take a while. How about <code>crypto</code> in Python files? This helps me speed up finding things.</p>
<pre><code>rg &quot;crypto&quot; --stats
.... (full output of the search)
1292 matches
1083 matched lines
232 files contained matches
36826 files searched
6296587 bytes printed
254562478 bytes searched
5.805867 seconds spent searching
1.559705 seconds</code></pre>
<h1 id="exclude-a-directory">Exclude a directory</h1>
<p>I do not want to search through our modules directory, only our code.</p>
<p>We can do this by:</p>
<pre><code>$ rg crypto -g &apos;!modules/&apos; -g &apos;!pypi/&apos;
</code></pre>
<h1 id="find-files"> Find Files</h1>
<p>Find all files that have the word &quot;cluster&quot; in them.</p>
<pre><code>rg --files | rg cluster</code></pre>
<p></p>]]></content:encoded></item><item><title><![CDATA[All You Need to Know About Big O Notation [Python Examples]]]></title><description><![CDATA[<p>By the end of this article, you&#x2019;ll thoroughly understand Big O notation. You&#x2019;ll also know how to use it in the real world, and even the mathematics behind it!</p><p>In computer science, <strong>time complexity</strong> is the computational <strong>complexity</strong> that describes the amount of <strong>time</strong> it takes</p>]]></description><link>https://skerritt.blog/big-o/</link><guid isPermaLink="false">637ba41ef95627003d46e6f6</guid><category><![CDATA[Algorithms]]></category><category><![CDATA[python]]></category><category><![CDATA[programming]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Wed, 21 Jun 2023 14:59:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1668902610778-96403019a7f5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDh8fHx8fHwyfHwxNjY5MTI5MTIx&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1668902610778-96403019a7f5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDh8fHx8fHwyfHwxNjY5MTI5MTIx&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="All You Need to Know About Big O Notation [Python Examples]"><p>By the end of this article, you&#x2019;ll thoroughly understand Big O notation. You&#x2019;ll also know how to use it in the real world, and even the mathematics behind it!</p><p>In computer science, <strong>time complexity</strong> is the computational <strong>complexity</strong> that describes the amount of <strong>time</strong> it takes to run an algorithm.</p><p>Big O notation is a method for determining how fast an algorithm is. Using Big O notation, we can learn whether our algorithm is fast or slow. This knowledge lets us design better algorithms.</p><p>This article is written using agnostic Python. That means it will be easy to port the Big O notation code over to Java, or any other language. If the code isn&#x2019;t agnostic, there&#x2019;s Java code accompanying it.</p><hr><h2 id="%E2%9D%93-how-do-we-measure-how-long-an-algorithm-takes-to-run">&#x2753; How Do We Measure How Long an Algorithm Takes to Run?</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-130.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1038" height="772" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-130.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-130.png 1000w, https://skerritt.blog/content/images/2023/06/image-130.png 1038w" sizes="(min-width: 720px) 720px"></figure><p>We could run an algorithm 10,000 times and measure the average time taken.</p><pre><code class="language-console">&#x279C; python3 -m timeit &apos;[print(x) for x in range(100)]&apos;
100 loops, best of 3: 11.1 msec per loop 
&#x279C; python3 -m timeit &apos;[print(x) for x in range(10)]&apos;
1000 loops, best of 3: 1.09 msec per loop
# We can see that the time per loop changes depending on the input!
</code></pre><p>Say we have an algorithm that takes a shopping list and prints out every item on the shopping list. If the shopping list has 3 items, it&#x2019;ll execute quickly. If it has 10 billion items, it&#x2019;ll take a long time.</p><p>What is the &#x201C;perfect&#x201D; input size to get the &#x201C;perfect&#x201D; measure of how long the algorithm takes?</p><p>Other things we need to consider:</p><ul><li>Different processor speeds exist.</li><li>Languages matter. Assembly is faster than Scratch; how do we consider this?</li></ul><p><strong>For this reason, we use Big O (pronounced Big Oh) notation.</strong></p><h2 id="%F0%9F%A4%94-what-is-big-o-notation">&#x1F914; What Is Big O Notation?</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-131.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1004" height="837" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-131.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-131.png 1000w, https://skerritt.blog/content/images/2023/06/image-131.png 1004w" sizes="(min-width: 720px) 720px"></figure><p>Big O is a formal notation that describes the behaviour of a function when the argument tends towards the maximum input. It was invented by <a href="https://www-history.mcs.st-andrews.ac.uk/Biographies/Bachmann.html?ref=skerritt.blog">Paul Bachmann</a>, <a href="https://en.wikipedia.org/wiki/Edmund_Landau?ref=skerritt.blog">Edmund Landau</a> and others between 1894 and 1820s. Popularised in the 1970s by <a href="https://www-cs-faculty.stanford.edu/~knuth/?ref=skerritt.blog">Donald Knuth</a>. Big O takes the upper bound. The worst-case results in the worst execution of the algorithm. For our shopping list example, the worst-case is an infinite list.</p><p>Instead of saying the input is 10 billion, or infinite - we say the input is n size. The exact size of the input doesn&#x2019;t matter, only how our algorithm performs with the worst input. We can still work out Big O without knowing the exact size of an input.</p><p>Big O is easy to read once we learn this table: The Big O Notation&#x2019;s Order of Growth:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2022/11/Screenshot-2022-11-21-at-16.16.18.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1448" height="320" srcset="https://skerritt.blog/content/images/size/w600/2022/11/Screenshot-2022-11-21-at-16.16.18.png 600w, https://skerritt.blog/content/images/size/w1000/2022/11/Screenshot-2022-11-21-at-16.16.18.png 1000w, https://skerritt.blog/content/images/2022/11/Screenshot-2022-11-21-at-16.16.18.png 1448w" sizes="(min-width: 720px) 720px"></figure><p>Where the further right they are, the longer it takes. <code>n</code> is the size of the input. Big O notation uses these functions to describe algorithm efficiency.</p><p>In our shopping list example, in the worst case of our algorithm, it prints out every item in the list sequentially. Since there are <code>n</code> items in the list, it takes O(n)<em>O</em>(<em>n</em>) polynomial time to complete the algorithm.</p><p>Other asymptotic (time-measuring) notations are:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2022/11/Screenshot-2022-11-21-at-16.17.16.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1444" height="214" srcset="https://skerritt.blog/content/images/size/w600/2022/11/Screenshot-2022-11-21-at-16.17.16.png 600w, https://skerritt.blog/content/images/size/w1000/2022/11/Screenshot-2022-11-21-at-16.17.16.png 1000w, https://skerritt.blog/content/images/2022/11/Screenshot-2022-11-21-at-16.17.16.png 1444w" sizes="(min-width: 720px) 720px"></figure><p><strong>Informally</strong> this is:</p><ul><li>Big Omega (best case)</li><li>Big Theta (average case)</li><li>Big O (worst case)</li></ul><p>Let&#x2019;s walk through every single column in our &#x201C;The Big O Notation Table&#x201D;.</p><h2 id="%F0%9F%9F%A2-constant-time">&#x1F7E2; Constant Time</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-132.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1090" height="801" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-132.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-132.png 1000w, https://skerritt.blog/content/images/2023/06/image-132.png 1090w" sizes="(min-width: 720px) 720px"><figcaption>No matter how many elements, it will always take x operations to perform. In this case, 2.</figcaption></figure><p>No matter how many elements, it will always take x operations to perform. In this case, 2. Constant algorithms do not scale with the input size, they are constant no matter how big the input. An example of this is addition. 1+2 takes the same time as 500+700. They may take more <strong>physical time</strong>, but we do not add more steps in the algorithm for the addition of big numbers. The underlying algorithm doesn&#x2019;t change at all.</p><p>We often see constant as O(1), but any number could be used and it would still be constant. We sometimes change the number to a 1, because it doesn&#x2019;t matter at all about how many steps it takes. What matters is that it takes a constant number of steps.</p><p>Constant time is the fastest of all Big O time complexities. The formal definition of constant time is:</p><p>It is upper-bounded by a constant</p><p>An example is:</p><pre><code class="language-python">def OddOrEven(n):
    return &quot;Even&quot; if n % 2 else &quot;Odd&quot;
</code></pre><p>Or in Java:</p><pre><code class="language-java">boolean isEven(double num) { return ((num % 2) == 0); }
</code></pre><p>In most programming languages, all integers have limits. Primitive operations (such as modulo, <code>%</code>) are all upper-bounded by this limit. If we go over this limit, we get an overflow error.</p><p>Because of this upper-bound, it satisfies O(1).</p><h1 id="%F0%9F%94%B5-logarithmic-time">&#x1F535; Logarithmic Time</h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-133.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1111" height="801" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-133.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-133.png 1000w, https://skerritt.blog/content/images/2023/06/image-133.png 1111w" sizes="(min-width: 720px) 720px"><figcaption>Log is less than O(1) with 1 element, but in Big O we don&apos;t care about element sizes</figcaption></figure><p>Here&#x2019;s a quick explainer of what a logarithm is.</p><p>$$Log_{3}^{9}$$</p><p>What is being asked here is &#x201C;3 to what power gives us 9?&#x201D; This is 3 to the power of 2 gives us 9, so the whole expression looks like this:</p><p>$$Log_{3}^{9} = 2$$</p><p>A logarithmic algorithm <strong>halves</strong> the list every time it&#x2019;s run.</p><p>Let&#x2019;s look at binary search. Given the below-sorted list:</p><pre><code class="language-python">a = [1, 2, 3, 4, 5, 6 , 7, 8, 9, 10]
</code></pre><p>We want to find the number &#x201C;2&#x201D;.</p><p>We implement Binary Search as:</p><pre><code class="language-python">def binarySearch(alist, item):
    first = 0
    last = len(alist)-1
    found = False

    while first &lt;= last and not found:
        midpoint = (first + last)//2
        if alist[midpoint] == item:
            found = True
        else:
            if item &lt; alist[midpoint]:
            last = midpoint-1
            else:
                first = midpoint+1

    return found
</code></pre><p>In English, this is:</p><ul><li>Go to the middle of the list</li><li>Check to see if that element is the answer</li><li>If it&#x2019;s not, check to see if that element is more than the item we want to find</li><li>If it is, ignore the right-hand side (all the numbers higher than the midpoint) of the list and choose a new midpoint.</li><li>Start over again, by finding the midpoint in the new list.</li></ul><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/binsearch.gif" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="773" height="406" srcset="https://skerritt.blog/content/images/size/w600/2023/06/binsearch.gif 600w, https://skerritt.blog/content/images/2023/06/binsearch.gif 773w" sizes="(min-width: 720px) 720px"></figure><p>The algorithm halves the input every single time it iterates. Therefore it is logarithmic. Other examples include:</p><ul><li><a href="https://www.geeksforgeeks.org/program-for-nth-fibonacci-number/?ref=skerritt.blog">Fibonacci number calculations</a></li><li><a href="https://en.wikipedia.org/wiki/Binary_search_tree?ref=skerritt.blog">Searching a Binary Search Tree</a></li><li><a href="https://www.cs.auckland.ac.nz/software/AlgAnim/AVL.html?ref=skerritt.blog">Searching AVL trees</a></li></ul><h1 id="%F0%9F%9F%A1-linear-time">&#x1F7E1; Linear Time</h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-138.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1090" height="801" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-138.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-138.png 1000w, https://skerritt.blog/content/images/2023/06/image-138.png 1090w" sizes="(min-width: 720px) 720px"><figcaption>Linear time increases linearly. [2, 2], [4, 4] and so on.</figcaption></figure><p>Linear time algorithms mean that every single element from the input is visited exactly once, O(n) times. As the size of the input, N, grows our algorithm&#x2019;s run time scales exactly with the size of the input.</p><blockquote><strong>Linear</strong> running <strong>time algorithms</strong> are widespread. <strong>Linear</strong> runtime means that the program visits every element from the input. <strong>Linear time</strong> complexity O(n) means that as the input grows, the <strong>algorithms</strong> take proportionally longer to complete.2 Apr 2019</blockquote><p>Remember our shopping list app from earlier? The algorithm ran in O(n) which is linear time!</p><p>Linear time is where every single item in a list is visited once, in a worst-case scenario.</p><p>To read out our shopping list, our algorithm <strong>has</strong> to read out each item. It can&#x2019;t half the list, or add more items that we didn&#x2019;t add. It has to list all n items, one at a time.</p><pre><code class="language-python">shopping_list = [&quot;Bread&quot;, &quot;Butter&quot;, &quot;The Nacho Libre soundtrack from the 2006 film Nacho Libre&quot;, &quot;Reusable Water Bottle&quot;]
for item in shopping_list:
    print(item)
</code></pre><p>Let&#x2019;s look at another example.</p><h3 id="the-largest-item-of-an-unsorted-array">The largest item of an unsorted array</h3><p>Given the list:</p><pre><code class="language-python">a = [2, 16, 7, 9, 8, 23, 12]
</code></pre><p>How do we work out what the largest item is?</p><p>We need to program it like this:</p><pre><code class="language-python">a = [2, 16, 7, 9, 8, 23, 12]
max_item = a[0]
for item in a:
    if item &gt; max_item:
        max_item = item
</code></pre><p>We have to go through every item in the list, 1 by 1.</p><h2 id="%F0%9F%94%B4-polynomial-time">&#x1F534; Polynomial Time</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-139.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1104" height="801" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-139.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-139.png 1000w, https://skerritt.blog/content/images/2023/06/image-139.png 1104w" sizes="(min-width: 720px) 720px"><figcaption>Notice how polynomial time dwarfs the others?</figcaption></figure><p>Notice how polynomial time dwarfs the others? Polynomial time is a polynomial function of the input. A polynomial function looks like n<sup>2</sup> or n<sup>3</sup> and so on.</p><p>If one loop through a list is O(n), 2 loops must be O(n<sup>2</sup>). For each loop, we go over the list once. For each item in that list, we go over the entire list once. Resulting in n2 operations.</p><pre><code class="language-python">a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in a:
    for x in a:
        print(&quot;x&quot;)
</code></pre><p>For each nesting on the same list, that adds an extra +1 to the powers.</p><p>A triple nested loop is O(n<sup>3</sup>).</p><p>Bubblesort is a good example of anO(n<sup>2</sup>) algorithm. The sorting algorithm takes the first number and swaps it with the adjacent number if they are in the wrong order. It does this for each number until all numbers are in the right order - and thus sorted.</p><pre><code class="language-python">def bubbleSort(arr):
    n = len(arr)
    
    # Traverse through all array elements
    for i in range(n):
    
        # Last i elements are already in place
        for j in range(0, n-i-1):
    
            # traverse the array from 0 to n-i-1
            # Swap if the element found is greater
            # than the next element
            if arr[j] &gt; arr[j+1] :
                arr[j], arr[j+1] = arr[j+1], arr[j]
    
# Driver code to test above
arr = [64, 34, 25, 12, 22, 11, 90]
    
bubbleSort(arr)
</code></pre><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/bubblesort.gif" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="500" height="300"></figure><p>As a side note, my professor refers to any algorithm with a time of polynomial or above as:</p><blockquote>A complete and utter disaster! This is a disaster! A catastrophe!</blockquote><p>But the thing with large time complexities is that they often show us that something can be quickened.</p><p>For instance, a problem I had. Given a sentence, how many of those words appear in the English Dictionary? We can imagine the O(n<sup>2</sup>) method. One <code>for loop</code> through the sentence, another through the dictionary.</p><pre><code class="language-python">dictionary = [&quot;a&quot;, &quot;an&quot;] # imagine if this was the dictionary
sentence = &quot;hello uu988j my nadjjrjejas is brandon nanndwifjasj banana&quot;.split(&quot; &quot;)

counter = 0
for word in sentence:
    for item in dictionary:
        if word == item:
            counter = counter + 1
</code></pre><p>O(n<sup>2</sup>)! A disaster! But, knowing that this is a disaster means we can speed it up. Dictionaries are sorted by default. What if we sort our list of words in the sentence, and checked each word that way? We only need to loop through the dictionary once. And if the word we want to check is less than the word we&#x2019;re on in the dictionary, we switch to the second word in the list.</p><p>Now our algorithm is O(n log n). We recognise that this isn&#x2019;t a disaster, so we can move on! <strong>Knowing time complexities isn&#x2019;t only useful in interviews. It&#x2019;s an essential tool to improve our algorithms.</strong></p><p>We can hasten many polynomial algorithms we construct using knowledge of <a href="https://skerritt.blog/dynamic-programming/">algorithmic design</a>.</p><h1 id="%E2%9D%8C-exponential-time">&#x274C; Exponential Time</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-140.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1133" height="801" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-140.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-140.png 1000w, https://skerritt.blog/content/images/2023/06/image-140.png 1133w" sizes="(min-width: 720px) 720px"></figure><p>Exponential time is 2<sup>n</sup>, where 2 depends on the permutations involved.</p><p>This algorithm is the slowest of them all. You saw how my professor reacted to polynomial algorithms. He was jumping up and down in furiosity at exponential algorithms!</p><p>Say we have a password consisting only of numbers (so that&#x2019;s 10 numbers, 0 through to 9). we want to crack a password which has a length of n, so to brute force through every combination we&#x2019;ll have 10<sup>n</sup> combinations to work through.</p><p>One example of exponential time is to <a href="https://skerritt.blog/a-primer-on-set-theory/">find all the subsets of a set.</a></p><pre><code class="language-console">&gt;&gt;&gt; subsets([&apos;&apos;])
[&apos;&apos;]
&gt;&gt;&gt; subsets([&apos;x&apos;])
[&apos;&apos;, &apos;x&apos;]
&gt;&gt;&gt; subsets([&apos;a&apos;, &apos;b&apos;])
[&apos;&apos;, &apos;a&apos;, &apos;b&apos;, &apos;ab&apos;]
</code></pre><p>We can see that when we have an input size of 2, the output size is 22=422=4.</p><p>Now, let&#x2019;s code up <code>subsets</code>.</p><pre><code class="language-python">from itertools import chain, combinations

def subsets(iterable):
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
</code></pre><p><a href="https://docs.python.org/3/library/itertools.html?ref=skerritt.blog#itertools-recipes">Taken from the documentation for itertools.</a></p><p>What&#x2019;s important here is to see that it exponentially grows depending on the input size. <a href="https://www.geeksforgeeks.org/power-set/?ref=skerritt.blog">Java code can be found here.</a></p><p>Exponential algorithms are horrific, but like polynomial algorithms we can learn a thing or two. Let&#x2019;s say we have to calculate 10<sup>4</sup>. We need to do this:</p><p>$$10 * 10 * 10 * 10 = 10^2 * 10^2$$</p><p>We have to calculate 10<sup>2</sup> twice! What if we store that value somewhere and use it later so we do not have to recalculate it? <a href="https://skerritt.blog/dynamic-programming/">This is the principle of Dynamic Programming, which you can read about here.</a></p><p>When we see an exponential algorithm, <a href="https://skerritt.blog/dynamic-programming/">dynamic programming</a> can often be used to speed it up.</p><p>Again, <strong>knowing time complexities allows us to build better algorithms.</strong></p><p>Here&#x2019;s our Big O notation graph where the numbers are reduced so we can see all the different lines.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-141.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1090" height="801" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-141.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-141.png 1000w, https://skerritt.blog/content/images/2023/06/image-141.png 1090w" sizes="(min-width: 720px) 720px"></figure><hr><h2 id="%F0%9F%98%8C-simplifying-big-o-notation">&#x1F60C; Simplifying Big O notation</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-142.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1078" height="730" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-142.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-142.png 1000w, https://skerritt.blog/content/images/2023/06/image-142.png 1078w" sizes="(min-width: 720px) 720px"></figure><p>Rarely will time complexity be as easy as counting how many for loops we have. What if our algorithm looks like \(O(n+n2)\)? We can simplify our algorithm using these simple rules:</p><h2 id="drop-the-constants">Drop the constants</h2><p>If we have an algorithm described as O(2n), we drop the 2 so it becomes O(n).</p><h2 id="drop-the-non-dominant-terms">Drop the non-dominant terms</h2><p>O(n&#xB2;+n) becomes O(n&#xB2;). Only keep the larger one in Big O.</p><p>If we have a sum such as O(b&#xB2;+a) we can&#x2019;t drop either without knowledge of what b and a are.</p><h2 id="is-that-it">Is that it?</h2><p>Yup! The hardest part is figuring out what our program&#x2019;s complexity is first. Simplifying is the easy part! Just remember the golden rule of Big O notation:</p><blockquote>&#x201C;What is the worst-case scenario here?&#x201D;</blockquote><hr><h2 id="%E2%98%81-other-big-o-times-to-learn-but-not-essential">&#x2601; Other Big O Times to Learn (But Not Essential)</h2><h3 id="%F0%9F%A5%87-on-log-n">&#x1F947; O(n log n)</h3><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-143.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1104" height="801" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-143.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-143.png 1000w, https://skerritt.blog/content/images/2023/06/image-143.png 1104w" sizes="(min-width: 720px) 720px"><figcaption>It falls between O(n) and O(n<sup>2</sup>)</figcaption></figure><p>It falls between O(n) and O(n<sup>2</sup>). <strong>This is the fastest time possible for a comparison sort.</strong> We cannot get any faster unless we use some special property, like Radix sort. O(n log n) is the fastest comparison sort time.</p><p>It&#x2019;s rather famous because Mergesort runs in O(n log n). Mergesort is a great algorithm not only because it sorts fast, but because the idea is used to build other algorithms.</p><p>Mergesort is used to teach <a href="https://skerritt.blog/divide-and-conquer-algorithms/">divide &amp; conquer algorithms</a>. And for good reason, it&#x2019;s a fantastic sorting algorithm that has roots outside of sorting.</p><p>Mergesort works by breaking down the list of numbers into individual numbers:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-144.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1480" height="780" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-144.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-144.png 1000w, https://skerritt.blog/content/images/2023/06/image-144.png 1480w" sizes="(min-width: 720px) 720px"></figure><p>And then sorting each list, before merging them:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-145.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1480" height="660" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-145.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-145.png 1000w, https://skerritt.blog/content/images/2023/06/image-145.png 1480w" sizes="(min-width: 720px) 720px"></figure><pre><code class="language-python">def mergeSort(alist):
    print(&quot;Splitting &quot;,alist)
    if len(alist)&gt;1:
        mid = len(alist)//2
        lefthalf = alist[:mid]
        righthalf = alist[mid:]

        mergeSort(lefthalf)
        mergeSort(righthalf)

        i=0
        j=0
        k=0
        while i &lt; len(lefthalf) and j &lt; len(righthalf):
            if lefthalf[i] &lt;= righthalf[j]:
                alist[k]=lefthalf[i]
                i=i+1
            else:
                alist[k]=righthalf[j]
                j=j+1
            k=k+1

        while i &lt; len(lefthalf):
            alist[k]=lefthalf[i]
            i=i+1
            k=k+1

        while j &lt; len(righthalf):
            alist[k]=righthalf[j]
            j=j+1
            k=k+1
    print(&quot;Merging &quot;,alist)

alist = [54,26,93,17,77,31,44,55,20]
mergeSort(alist)
print(alist)
</code></pre><p><a href="https://skerritt.blog/divide-and-conquer-algorithms#merge-sort-">Read more on Mergesort here.</a></p><h3 id="%F0%9F%91%BF-on">&#x1F47F; O(n!)</h3><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-146.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1076" height="801" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-146.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-146.png 1000w, https://skerritt.blog/content/images/2023/06/image-146.png 1076w" sizes="(min-width: 720px) 720px"><figcaption>Factorial dwarfs all over complexities.</figcaption></figure><p>Notice the <code>le10</code> at the top? This one is so large, it makes all other times look constant!</p><p>This time complexity is often used as a joke, referring to Bogo Sort. I have yet to find a real-life (not-a-joke) algorithm that runs in O(n!) that isn&#x2019;t an algorithm calculating O(6!) or the likes.</p><h1 id="%F0%9F%A7%AE-how-to-calculate-big-o-notation-for-our-own-algorithms-with-examples">&#x1F9EE; How to Calculate Big O Notation for Our Own Algorithms with Examples</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-147.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="1102" height="864" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-147.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-147.png 1000w, https://skerritt.blog/content/images/2023/06/image-147.png 1102w" sizes="(min-width: 720px) 720px"></figure><p>Our own algorithms will normally be based on some famous algorithm that already has a Big O notation. If it&#x2019;s not, do not worry! Working out the Big O of our algorithm is easy.</p><p>Just think:</p><blockquote>&#x201C;What is the absolute worst input for my program?&#x201D;</blockquote><p>Take, for instance, a sequential searching algorithm.</p><pre><code class="language-python">def search(listInput, toFind):
    for counter, item in enumerate(listInput):
        if toFind == item:
            return (counter, item)
    return &quot;did not find the item!&quot;
</code></pre><p>The best input would be:</p><pre><code class="language-python">search([&quot;apples&quot;], &quot;apples&quot;)
</code></pre><p>But the worst input is if the item was at the end of a long list.</p><pre><code class="language-python">search([&quot;apples&quot;, &quot;oranges&quot;, &quot;The soundtrack from the 2006 film Nacho Libre&quot;, &quot;Shrek&quot;], &quot;Shrek&quot;)
</code></pre><p>The worst-case scenario is O(n), because we have to go past every item in the list to find it.</p><p>What if our search algorithm was binary search? We learnt that binary search divides the list into half every time. This sounds like <code>log n</code>!</p><p>What if our binary search looks for an object, and then looks to find other similar objects?</p><pre><code class="language-python"># here we want to find the film shrek, find its IMDB rating and find other films with that IMDB rating. We are using binary search, then sequential search
toFind = {title: &quot;Shrek&quot;, IMDBrating: None}
ret = search(toFind)
ret = search(ret[&apos;IMDBrating&apos;])
</code></pre><p>We find Shrek with an IMDB score of 7.8. But we&#x2019;re only sorted on the title, not the IMDB rating. We have to use a sequential search to find all other films with the same rating.</p><p>Binary search is O(log n) and sequential search is O(n), this makes our algorithm O(n log n). This isn&#x2019;t a disaster, so we can be sure it&#x2019;s not a terrible algorithm.</p><p>Even in instances where our algorithms are not strictly related to other algorithms, we can still compare them to things we know. O(log n) means halving. O(n2) means a nested for loop.</p><p>One last thing, we don&#x2019;t always deal with <code>n</code>. Take this below algorithm:</p><pre><code class="language-python">x = [1, 2, 3, 4, 5]
y = [2, 6]
y = iter(y)
counter = 0
total = 0.0
while counter != len(x):
    # cycles through the y list.
    # multiplies 2 by 1, then 6 by 2. Then 2 by 3. 
    total = total + x[counter] * next(y)
    counter += 1
print(total)
</code></pre><p>We have 2 inputs, x and y. Our notation is then O(x + y). Sometimes we cannot make our notation smaller without knowing more about the data.</p><h1 id="%F0%9F%A4%AF-big-o-notation-cheat-sheet">&#x1F92F; Big O Notation Cheat Sheet</h1><p>I made this little infographic for you! The &#x201C;add +1 for every nested for loop&#x201D; depends on the for loop, as we saw earlier. But explaining that all over again would take up too much space &#x1F605;</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-148.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="800" height="2000" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-148.png 600w, https://skerritt.blog/content/images/2023/06/image-148.png 800w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-149.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="800" height="1403" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-149.png 600w, https://skerritt.blog/content/images/2023/06/image-149.png 800w" sizes="(min-width: 720px) 720px"></figure><hr><h2 id="%F0%9F%8E%93-how-to-calculate-big-o-notation-of-a-function-discrete-maths">&#x1F393; How to Calculate Big O Notation of a Function (Discrete Maths)</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-150.png" class="kg-image" alt="All You Need to Know About Big O Notation [Python Examples]" loading="lazy" width="795" height="574" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-150.png 600w, https://skerritt.blog/content/images/2023/06/image-150.png 795w" sizes="(min-width: 720px) 720px"></figure><p>Okay, this is where it gets hard. A lot of complaints against Big O notation is along the lines of:</p><blockquote>&#x201C;You didn&#x2019;t really teach it, to really understand it you have to understand the maths!&#x201D;</blockquote><p>And I kinda agree. The surface-level knowledge above will be good for most interviews, but the stuff here is the stuff needed to master Big O notation.</p><p>Just as a reminder, we want to master asymptotic time complexity as it allows us to create better algorithms.</p><p>I&#x2019;m going to be writing out the formal notation, and then explaining it simply. <strong>Over-simplification causes misinformation</strong>, so if you are studying for a test take your simplifications as generalities and not the truth. Mathematics is the whole truth, and you would be better off studying the maths rather than studying my simplifications. As I once read on the internet:</p><blockquote>Shut up and calculate.</blockquote><h3 id="is-big-o-notation-the-worst-case">Is Big O Notation the Worst Case?</h3><p>First things first, when I said:</p><blockquote>Big O notation is the worst-case</blockquote><p><strong>That&#x2019;s not true at all</strong>. It&#x2019;s a white lie designed to help you learn the basics. Often used to get us to know enough to <em>just</em> pass interviews, but not enough to use it in the real world.</p><p>The formal definition of Big O notation is:</p><blockquote>The upper-bounded time limit of the algorithm</blockquote><p>Now, this often means &#x201C;the worst-case&#x201D; but not always. We can put upper bounds on whatever we want. But more often than not, we put upper bounds on the worst-case. In one of our examples, we&#x2019;ll come across a weird formula where &#x201C;the worst case&#x201D; isn&#x2019;t necessarily the one we choose for Big O.</p><p>This is an important distinction to make because some caveats will confuse us otherwise.</p><p>Given 2 positive functions, f(n) and g(n) we say f(n) is O(g(n)), written \(f(n) \in O(g(n))\), if there are constants c and n_0 such that:</p><p>$$f(n) \le c * g(n) \forall &#xA0;\geq &#xA0;n_o$$</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">&#x1F47D;</div><div class="kg-callout-text"><em>Asymptotic notation leans heavily into set theory. Check out my article on set theory below:</em></div></div><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://skerritt.blog/sets/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Set Theory for Programmers</div><div class="kg-bookmark-description">If you&#x2019;ve spent time on HackerRank or LeetCode, you might have noticed most of the optimal solutions use Set Theory. By reading this article, you will gain a deeper knowledge into set theory and how to use it to create optimal algorithms. Set Theory was invented (or found, depending</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://skerritt.blog/favicon.ico" alt="All You Need to Know About Big O Notation [Python Examples]"><span class="kg-bookmark-author">Skerritt.blog</span><span class="kg-bookmark-publisher">Autumn Skerritt</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1673264809315-9d7c34f0a22d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDI5fHx8fHx8Mnx8MTY3MzM2NjgyNg&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="All You Need to Know About Big O Notation [Python Examples]"></div></a></figure><p>Also, sometimes \(n_{0}\)&#x200B; is called k. But c stays the same.</p><p>This looks confusing but is just a fancy way of saying that the function (algorithm) is part of another function (the Big O notation used). Simplifying again: Our algorithm falls within the range of a Big O notation time complexity (O(n), O(log n), etc). So our algorithm <em>is</em> that time complexity (to simplify it).</p><p>Let&#x2019;s see an example:</p><p>$$7n - 4 \in O(n)$$</p><p>Here we are claiming that 7n - 4 is in O(n) time. In formal Big O notation, we don&apos;t say it <strong>is</strong> that time. We say it falls within the range of that time. </p><p>We need to find constants c and n_0 such that \(7n-4 &lt;= cn\) for all \(n &gt;= n_{0}\). One choice is c = 7 and \(n_{o} = 1. 7 * 7 = 42 - 4 = 38\) and 7 * 1 = 7 so for all where n &gt;= 7 this function holds true. This is just one of the many choices because any real number c &gt;= 7 and any integer n_0 &gt;= 1 would be okay. Another way to rephrase this is:</p><p>$$7n-4 \le 7n \; where \; n \geq 1$$</p><p>The left-hand side, 7n-4 is f(n). c = 10. g(n) = n. Therefore we can say f(n) =O(n) because g(n) = n. We say f(n) in O(n). All we have to do is substitute values into the formula until we find values for c and n that work. Let&apos;s do 10 examples now.</p><h2 id="example-1">Example 1</h2><p>$$f(n) = 4n^2 + 16n + 2$$</p><blockquote>Is f(n) O(n4)?</blockquote><p>We need to take this function:</p><p>$$f(n) = 4n^2 + 16n + 2$$</p><p>and say &#x201C;is this less than some constant times n4?&#x201D; We need to find out if there is such a constant.</p><p>$$n^2 + 16n + 2 \le n^4$$</p><p>Let&#x2019;s do a chart. If n=0 we get:</p><p>$$0 + 0 + 2 = 2 \le 0$$</p><p>This isn&#x2019;t true, so N = 0 is not true.</p><p>When n=1:</p><p>$$ 4 * 1 * 16 * 2 = 22 \le 1^4 = 22 \le 1$$</p><p>Is not true. Let&#x2019;s try it again with n = 3.</p><p>$$50 \le 16$$</p><p>Not true, so let&#x2019;s try another one. n=3.</p><p>$$86 \le 3^3 = 86 \le 81$$</p><p>Not true. Looks like the next one should work as we are approaching the tipping point. n=4.</p><p>$$ 130 \le 256$$</p><p>This is <strong>true. W</strong>hen n=4 or a greater number then this function where it&#x2019;s less than N4 becomes True. When C=1, N&#x2265;4 this holds true.</p><p>The answer to the question &#x201C;is this function, n2+16n+2<em>n</em>, Big O of n4 true?&#x201D; Yes, when c=1 and n&#x2265;4.&#x201D;</p><p>Note: I&#x2019;m saying c=1 but I&#x2019;m not writing \(c_n\) every time. Later on, using c will become important. But for these starter examples we&#x2019;ll just assume c=1 until said otherwise.</p><h2 id="example-2">Example 2</h2><p>$$3n^2 + n + 16$$</p><blockquote>Is this O(n<sup>2</sup>)?</blockquote><p>We know that n &lt;= n^2 for all n &gt;= 1. Also, 16 &lt;= n<sup>2</sup> for n &gt;= 4. </p><p>So:</p><p>$$3n^2 + n + 16 \le 3n^2 + n^2 + n^2 = 5n^2$$</p><p>for all n &gt;= 4. The constant C is 5, and n_0 = 3.</p><h2 id="example-3">Example 3</h2><p>$$13n^3 + 7n \log \; n + 3$$</p><blockquote>is O(n<sup>3</sup>)</blockquote><p><br>Because log n &gt;= n<sup>2</sup> for all n &gt;= 1, and for similar reasons as above we may conclude that: \(13n^3 + 6n ; n ; log ; n ; + 3 \le 21 n^3\) for all &apos;large enough&apos; n. In this instance, c = 21.</p><h2 id="example-4">Example 4</h2><p>$$45n^5 - 10n^2 + 6n - 12$$</p><blockquote>is O(n<sup>2</sup>)? </blockquote><p>Any polynomial \(a_{k} n^k + ... + a_{2} n^2 + a_{1} n + a_{0}\) with \(a_{k} &gt; 0\) is O(n<sup>k</sup>).</p><p> Along the same lines, we can argue that any polynomial \(a_{k} n^k + ... + a_2 n^2 + a_1 n + a-0\) with \(a_k &gt; 0\) is also O(n<sup>j</sup>) for all j &gt;= k. Therefore \(45n^5 - 10n^2 + 6n - 12\) is O(n<sup>2</sup>) (and is also O(n<sup>8</sup>) or O(n<sup>9</sup>) or O(n<sup>k</sup>) for any n &gt;= 5). </p><h2 id="example-5">Example 5</h2><p>$$\sqrt{n}$$</p><blockquote>is O(n)? </blockquote><p>This doesn&apos;t hold true. \(\sqrt{n} = n^{1/2}\). Therefore \(O(n^{1/2}) &lt; O(n)\). I hope you appreciate the easy example to break up the hard maths &#x1F609;</p><h2 id="example-6">Example 6</h2><p><br>$$ 3 \log_{n} + \log \log n$$</p><blockquote>is O(log n)?</blockquote><p>First we have this equality that \(log n &lt;= n\) for every n &gt;= 1. We can put a double log here like so: \(log log n &lt;= log n\). Log log n is smaller than log n. We replaced &quot;n&quot; with &quot;log n&quot; on both sides of log n &lt;= n. So: </p><p>$$3 \; log \; n + \; log \; log \; n \le 4 \; log \; n$$</p><p>So:</p><p>$$c = 4, n_0 = 1$$</p><h2 id="example-7">Example 7</h2><p>$$log \; n$$</p><blockquote>is \(log \; n &lt; O(\sqrt{n})\)</blockquote><p>Log n grows slower than any function where this holds: <br><br>\(log \ m \le m^\epsilon\) for every \(\epsilon &gt; 0\) no matter how small it is, as long as it is positive.</p><p>Using this inequality if we plug in \(\epsilon = \frac{1}{2}\) and we plug that into our equation \(\sqrt{m} = m^{\frac{1}{2}}\).</p><p>Knowing that \(log \ m \le m^\epsilon\) we know that \(O(log \ n) &lt; O(\sqrt{n})\)</p><h2 id="example-8">Example 8</h2><p>$$2n + 3$$</p><blockquote>What is the Big O of this?</blockquote><p>$$2n + 3 \le 10n, n &#xA0;\geq 1$$</p><p>$$f(n) = O(n)$$.</p><p>This is because n is more than or equal to 1, it will always be larger than g(n) which is \(2n + 3\). Therefore, we have \(O(n)\).</p><h2 id="example-9">Example 9</h2><p>$$2n + 3 \le 10n$$</p><p>We don&apos;t have to write 10, it can be whatever we want so long as the equation holds true.</p><p>$$2n + 3 \le 2n + 3n$$</p><p>$$2n + 3 \le 5n, n \geq 1$$</p><p>Therefore \(f(n) = O(n)\).</p><p>Or we can write:</p><p>$$2n + 3 \le 5n^2 , n \geq 1$$</p><p>$$f(n) = 2n + 3$$</p><p>$$c = 5$$</p><p>$$g(n) = n^2$$</p><p>Can this same function be both \(O(n)\) and \(O(n^2)\)? Yes. It can be. This is where our definition of big o comes into play. It&apos;s the upper bound limit. We can say it is \(n^2, 2^n\) and any higher. But we cannot say it&apos;s lower.</p><p>When we write big o, we often want to use the closet function. Otherwise, we could say that every algorithm has an upper bound of \(O(2^n)\), which isn&apos;t true. Note: what we want to do (choose the closet function) &#xA0;is just a personal preference for most courses. All functions which work, which are the upper bound, are true.</p><p><a href="https://www.youtube.com/watch?v=A03oI0znAoc&amp;ref=skerritt.blog">There&apos;s a fantastic video on this strange concept here</a> (and I took this example from there). </p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/A03oI0znAoc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="1.8.1 Asymptotic Notations Big Oh - Omega - Theta #1"></iframe></figure><h1 id="summary">Summary</h1><p>Big O represents how long an algorithm takes but sometimes we care about how much memory (space complexity) an algorithm takes too. If you&apos;re ever stuck, come back to this page and check out the infographics!<br></p><p><br><br><br></p>]]></content:encoded></item><item><title><![CDATA[Timsort — the fastest sorting algorithm you’ve never heard of]]></title><description><![CDATA[<p>Timsort: A very fast , O(n log n), stable sorting algorithm built for the real world&#x200A;&#x2014;&#x200A;not constructed in academia.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-123.png" class="kg-image" alt loading="lazy" width="480" height="360"><figcaption><a href="https://www.youtube.com/watch?v=1wAOy88WxmY&amp;ref=skerritt.blog">Image from here.</a></figcaption></figure><p>Timsort is a sorting algorithm that is efficient for real-world data and not created in an academic laboratory. Tim Peters created Timsort for the</p>]]></description><link>https://skerritt.blog/timsort/</link><guid isPermaLink="false">6393b93d626d47003cac581e</guid><category><![CDATA[Popular]]></category><category><![CDATA[Algorithms]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Tue, 20 Jun 2023 15:40:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1670509917257-ea50fa82f5fa?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDEwfHx8fHx8Mnx8MTY3MDYyNTY1NQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1670509917257-ea50fa82f5fa?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDEwfHx8fHx8Mnx8MTY3MDYyNTY1NQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Timsort&#x200A;&#x2014;&#x200A;the fastest sorting algorithm you&#x2019;ve never heard of"><p>Timsort: A very fast , O(n log n), stable sorting algorithm built for the real world&#x200A;&#x2014;&#x200A;not constructed in academia.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-123.png" class="kg-image" alt="Timsort&#x200A;&#x2014;&#x200A;the fastest sorting algorithm you&#x2019;ve never heard of" loading="lazy" width="480" height="360"><figcaption><a href="https://www.youtube.com/watch?v=1wAOy88WxmY&amp;ref=skerritt.blog">Image from here.</a></figcaption></figure><p>Timsort is a sorting algorithm that is efficient for real-world data and not created in an academic laboratory. Tim Peters created Timsort for the Python programming language in 2001. Timsort first analyses the list it is trying to sort and then chooses an approach based on the analysis of the list.</p><p>Since the algorithm has been invented it has been used as the default sorting algorithm in Python, <a href="https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6804124&amp;ref=skerritt.blog">Java</a>, the <a href="http://www.kiwidoc.com/java/l/x/android/android/5/p/java.util/c/TimSort?ref=skerritt.blog">Android </a>Platform, and in GNU Octave.</p><p>Timsort&#x2019;s <a href="https://skerritt.blog/big-o/">big O notation</a> is O(n log n). To learn about Big O notation, read <a href="https://skerritt.blog/big-o/">this</a>.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-124.png" class="kg-image" alt="Timsort&#x200A;&#x2014;&#x200A;the fastest sorting algorithm you&#x2019;ve never heard of" loading="lazy" width="800" height="277" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-124.png 600w, https://skerritt.blog/content/images/2023/06/image-124.png 800w" sizes="(min-width: 720px) 720px"></figure><p>Timsort&#x2019;s sorting time is the same as Mergesort, which is faster than most of the other sorts you might know. Timsort actually makes use of Insertion sort and Mergesort, as you&#x2019;ll see soon.</p><p>Peters designed Timsort to use already-ordered elements that exist in most real-world data sets. It calls these already-ordered elements &#x201C;natural runs&#x201D;. It iterates over the data collecting the elements into runs and simultaneously merging those runs together into one.</p><hr><h2 id="the-array-has-fewer-than-64-elements-in-it">The array has fewer than 64 elements in it</h2><p>If the array we are trying to sort has fewer than 64 elements in it, Timsort will execute an insertion sort.</p><p>An insertion sort is a simple sort which is most effective on small lists. It is quite slow at larger lists, but very fast with small lists. The idea of an insertion sort is as follows:</p><ul><li>Look at elements one by one</li><li>Build up sorted list by inserting the element at the correct location</li></ul><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-125.png" class="kg-image" alt="Timsort&#x200A;&#x2014;&#x200A;the fastest sorting algorithm you&#x2019;ve never heard of" loading="lazy" width="800" height="367" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-125.png 600w, https://skerritt.blog/content/images/2023/06/image-125.png 800w" sizes="(min-width: 720px) 720px"></figure><p>In this instance we are inserting the newly sorted elements into a new sub-array, which starts at the start of the array.</p><p>Here&#x2019;s a gif showing insertion sort:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/sort-1.gif" class="kg-image" alt="Timsort&#x200A;&#x2014;&#x200A;the fastest sorting algorithm you&#x2019;ve never heard of" loading="lazy" width="500" height="300"></figure><hr><h2 id="more-about-runs">More about runs</h2><p>If the list is larger than 64 elements than the algorithm will make a first pass through the list looking for parts that are strictly increasing or decreasing. If the part is decreasing, it will reverse that part.</p><p>So if the run is decreasing, it&#x2019;ll look like this (where the run is in bold):</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-126.png" class="kg-image" alt="Timsort&#x200A;&#x2014;&#x200A;the fastest sorting algorithm you&#x2019;ve never heard of" loading="lazy" width="369" height="197"></figure><p>If not decreasing, it&#x2019;ll look like this:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-127.png" class="kg-image" alt="Timsort&#x200A;&#x2014;&#x200A;the fastest sorting algorithm you&#x2019;ve never heard of" loading="lazy" width="316" height="195"></figure><p>The minrun is a size which is determined based on the size of the array. The algorithm selects it so that most runs in a random array are, or become minrun, in length. Merging 2 arrays is more efficient when the number of runs is equal to, or slightly less than, a power of two. Timsort chooses minrun to try to ensure this efficiency, by making sure minrun is equal to or less than a power of two.</p><p>The algorithm chooses minrun from the range 32 to 64 inclusive. It chooses minrun such that the length of the original array, when divided by minrun, is equal to or slightly less than a power of two.</p><p>If the length of the run is less than minrun, you calculate the length of that run away from minrun. Using this new number, you grab that many items ahead of the run and perform an insertion sort to create a new run.</p><p>So if minrun is 63 and the length of the run is 33, you do 63&#x2013;33 = 30. You then grab 30 elements from in front of the end of the run, so this is 30 items from run[33] and then perform an insertion sort to create a new run.</p><p>After this part has completed we should now have a bunch of sorted runs in a list.</p><hr><h2 id="merging">Merging</h2><p>Timsort now performs mergesort to merge the runs together. However, Timsort makes sure to maintain stability and merge balance whilst merge sorting.</p><p>To maintain stability we should not exchange 2 numbers of equal value. This not only keeps their original positions in the list but enables the algorithm to be faster. We will shortly discuss the merge balance.</p><p>As Timsort finds runs, it adds them to a stack. A simple stack would look like this:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-128.png" class="kg-image" alt="Timsort&#x200A;&#x2014;&#x200A;the fastest sorting algorithm you&#x2019;ve never heard of" loading="lazy" width="264" height="254"></figure><p>Imagine a stack of plates. You cannot take plates from the bottom, so you have to take them from the top. The same is true about a stack.</p><p>Timsort tries to balance two competing needs when mergesort runs. On one hand, we would like to delay merging as long as possible in order to exploit patterns that may come up later. But we would like even more to do the merging as soon as possible to exploit the run that the run just found is still high in the memory hierarchy. We also can&#x2019;t delay merging &#x201C;too long&#x201D; because it consumes memory to remember the runs that are still unmerged, and the stack has a fixed size.</p><p>To make sure we have this compromise, Timsort keeps track of the three most recent items on the stack and creates two laws that must hold true of those items:</p><ol><li>A &gt; B + C</li><li>B &gt; C</li></ol><p>Where A, B and C are the three most recent items on the stack.</p><p>In the words of Tim Peters himself:</p><blockquote><em>What turned out to be a good compromise maintains two invariants on the stack entries, where A, B and C are the lengths of the three righmost not-yet merged slices</em></blockquote><p>Usually, merging adjacent runs of different lengths in place is hard. What makes it even harder is that we have to maintain stability. To get around this, Timsort sets aside temporary memory. It places the smaller (calling both runs A and B) of the two runs into that temporary memory.</p><h2 id="galloping">Galloping</h2><p>While Timsort is merging A and B, it notices that one run has been &#x201C;winning&#x201D; many times in a row. If it turned out that the run A consisted of entirely smaller numbers than the run B then the run A would end up back in its original place. Merging the two runs would involve a lot of work to achieve nothing.</p><p>More often than not, data will have some preexisting internal structure. Timsort assumes that if a lot of run A&#x2019;s values are lower than run B&#x2019;s values, then it is likely that A will continue to have smaller values than B.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-129.png" class="kg-image" alt="Timsort&#x200A;&#x2014;&#x200A;the fastest sorting algorithm you&#x2019;ve never heard of" loading="lazy" width="356" height="193"></figure><p>Image of 2 example runs, A and B. Runs have to be strictly increasing or decreasing, hence why these numbers were picked.</p><p>Timsort will then enter galloping mode. Instead of checking A[0] and B[0] against each other, Timsort performs a binary search for the appropriate position of b[0] in a[0]. This way, Timsort can move a whole section of A into place. Then Timsort searches for the appropriate location of A[0] in B. Timsort will then move a whole section of B can at once, and into place.</p><p>Let&#x2019;s see this in action. Timsort checks B[0] (which is 5) and using a binary search it looks for the correct location in A.</p><p>Well, B[0] belongs at the back of the list of A. Now Timsort checks for A[0] (which is 1) in the correct location of B. So we&#x2019;re looking to see where the number 1 goes. This number goes at the start of B. We now know that B belongs at the end of A and A belongs at the start of B.</p><p>It turns out, this operation is not worth it if the appropriate location for B[0] is very close to the beginning of A (or vice versa). so gallop mode quickly exits if it isn&#x2019;t paying off. Additionally, Timsort takes note and makes it harder to enter gallop mode later by increasing the number of consecutive A-only or B-only wins required to enter. If gallop mode is paying off, Timsort makes it easier to reenter.</p><p>In short, Timsort does 2 things incredibly well:</p><ul><li>Great performance on arrays with preexisting internal structure</li><li>Being able to maintain a stable sort</li></ul><p>Previously, in order to achieve a stable sort, you&#x2019;d have to zip the &#xA0;items in your list up with integers, and sort it as an array of tuples.</p><hr><h2 id="code">Code</h2><p>If you&#x2019;re not interested in the code, feel free to skip this part. There&#x2019;s some more information below this section.</p><pre><code class="language-python"># based off of this code https://gist.github.com/nandajavarma/a3a6b62f34e74ec4c31674934327bbd3
# Brandon Skerritt
# https://skerritt.tech

def binary_search(the_array, item, start, end):
    if start == end:
        if the_array[start] &gt; item:
            return start
        else:
            return start + 1
    if start &gt; end:
        return start

    mid = round((start + end)/ 2)

    if the_array[mid] &lt; item:
        return binary_search(the_array, item, mid + 1, end)

    elif the_array[mid] &gt; item:
        return binary_search(the_array, item, start, mid - 1)

    else:
        return mid

&quot;&quot;&quot;
Insertion sort that timsort uses if the array size is small or if
the size of the &quot;run&quot; is small
&quot;&quot;&quot;
def insertion_sort(the_array):
    l = len(the_array)
    for index in range(1, l):
        value = the_array[index]
        pos = binary_search(the_array, value, 0, index - 1)
        the_array = the_array[:pos] + [value] + the_array[pos:index] + the_array[index+1:]
    return the_array

def merge(left, right):
    &quot;&quot;&quot;Takes two sorted lists and returns a single sorted list by comparing the
    elements one at a time.
    [1, 2, 3, 4, 5, 6]
    &quot;&quot;&quot;
    if not left:
        return right
    if not right:
        return left
    if left[0] &lt; right[0]:
        return [left[0]] + merge(left[1:], right)
    return [right[0]] + merge(left, right[1:])

def timsort(the_array):
    runs, sorted_runs = [], []
    length = len(the_array)
    new_run = [the_array[0]]

    # for every i in the range of 1 to length of array
    for i in range(1, length):
        # if i is at the end of the list
        if i == length - 1:
            new_run.append(the_array[i])
            runs.append(new_run)
            break
        # if the i&apos;th element of the array is less than the one before it
        if the_array[i] &lt; the_array[i-1]:
            # if new_run is set to None (NULL)
            if not new_run:
                runs.append([the_array[i]])
                new_run.append(the_array[i])
            else:
                runs.append(new_run)
                new_run = []
        # else if its equal to or more than
        else:
            new_run.append(the_array[i])

    # for every item in runs, append it using insertion sort
    for item in runs:
        sorted_runs.append(insertion_sort(item))
    
    # for every run in sorted_runs, merge them
    sorted_array = []
    for run in sorted_runs:
        sorted_array = merge(sorted_array, run)

    print(sorted_array)

timsort([2, 3, 1, 5, 6, 7])
</code></pre><p>The source code below is based on mine and Nanda Javarma&#x2019;s work. The source code is not complete, nor is it similar to Python&#x2019;s offical sorted() source code. This is just a dumbed-down Timsort I implemented to get a general feel of Timsort. If you want to see Timsort&#x2019;s original source code in all its glory, check it out <a href="https://github.com/python/cpython/blob/master/Objects/listobject.c?ref=skerritt.blog">here</a>. Timsort is offically implemented in C, not Python.</p><p>Timsort is actually built right into Python, so this code only serves as an explainer. To use Timsort simply write:</p><pre><code class="language-python">list.sort()
</code></pre><p>Or</p><pre><code class="language-python">sorted(list)
</code></pre><p>If you want to master how Timsort works and get a feel for it, I highly suggest you try to implement it yourself!</p><p>This article is based on Tim Peters&#x2019; original introduction to Timsort, found <a href="https://bugs.python.org/file4451/timsort.txt?ref=skerritt.blog">here</a>.</p>]]></content:encoded></item><item><title><![CDATA[Greedy Algorithms In Python]]></title><description><![CDATA[<p><strong>Greedy algorithms</strong> aim to make the optimal choice at that given moment. Each step it chooses the optimal choice, without knowing the future. It attempts to find the globally optimal way to solve the entire problem using this method.</p><p>Why Are Greedy Algorithms Called Greedy?</p><p>We call algorithms <em>greedy</em> when</p>]]></description><link>https://skerritt.blog/greedy-algorithms/</link><guid isPermaLink="false">63a477aaa1c310003d1e6214</guid><category><![CDATA[Algorithms]]></category><category><![CDATA[python]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Tue, 20 Jun 2023 10:03:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1671659420749-d56efede6df4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDh8fHx8fHwyfHwxNjcxODc2MjA1&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1671659420749-d56efede6df4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDh8fHx8fHwyfHwxNjcxODc2MjA1&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Greedy Algorithms In Python"><p><strong>Greedy algorithms</strong> aim to make the optimal choice at that given moment. Each step it chooses the optimal choice, without knowing the future. It attempts to find the globally optimal way to solve the entire problem using this method.</p><p>Why Are Greedy Algorithms Called Greedy?</p><p>We call algorithms <em>greedy</em> when they utilise the greedy property. The greedy property is:</p><blockquote>At that exact moment in time, what is the optimal choice to make?</blockquote><p>Greedy algorithms are greedy. They do not look into the future to decide the global optimal solution. They are only concerned with the optimal solution locally. This means that <strong>the overall optimal solution may differ from the solution the algorithm chooses.</strong></p><p>They never look backwards at what they&#x2019;ve done to see if they could optimise globally. This is the main difference between Greedy and <a href="https://skerritt.blog/dynamic-programming/">Dynamic Programming</a>.</p><p>To be extra clear, one of the most Googled questions about greedy algorithms is:</p><blockquote>&#x201C;What problem-solving strategies don&#x2019;t guarantee solutions but make efficient use of time?&#x201D;</blockquote><p>The answer is &#x201C;Greedy algorithms&#x201D;. They don&#x2019;t guarantee solutions but are very time efficient. However, in the next section, we&#x2019;ll learn that sometimes Greedy solutions give us the optimal solutions.</p><hr><h2 id="what-are-greedy-algorithms-used-for">What Are Greedy Algorithms Used For?</h2><p>Greedy algorithms are quick. A lot faster than the two other alternatives (<a href="https://skerritt.blog/divide-and-conquer-algorithms/">Divide &amp; Conquer</a>, and <a href="https://skerritt.blog/dynamic-programming/">Dynamic Programming</a>). They&#x2019;re used because they&#x2019;re fast.</p><p>Sometimes, Greedy algorithms give the global optimal solution every time. Some of these algorithms are:</p><ul><li><a href="https://www.cs.cmu.edu/~deva/papers/tracking2011.pdf?ref=skerritt.blog">Dijkstra&#x2019;s Algorithm</a></li><li><a href="https://en.wikipedia.org/wiki/Kruskal%27s_algorithm?ref=skerritt.blog">Kruskal&#x2019;s algorithm</a></li><li><a href="https://en.wikipedia.org/wiki/Prim%27s_algorithm?ref=skerritt.blog">Prim&#x2019;s algorithm</a></li><li><a href="https://en.wikipedia.org/wiki/Huffman_tree?ref=skerritt.blog">Huffman trees</a></li></ul><p>These algorithms are Greedy, and their Greedy solution gives the optimal solution.</p><p>We&#x2019;re going to explore greedy algorithms using examples, and learning how it all works.</p><hr><h2 id="how-do-i-create-a-greedy-algorithm">How Do I Create a Greedy Algorithm?</h2><p>Your algorithm needs to follow this property:</p><blockquote>At that exact moment in time, what is the optimal choice to make?</blockquote><p>And that&#x2019;s it. There isn&#x2019;t much to it. Greedy algorithms are easier to code than <a href="https://skerritt.blog/divide-and-conquer-algorithms/">Divide &amp; Conquer</a> or <a href="https://skerritt.blog/dynamic-programming/">Dynamic Programming</a>.</p><hr><h1 id="counting-change-using-greedy">Counting Change Using Greedy</h1><p>Imagine you&#x2019;re a vending machine. Someone gives you &#xA3;1 and buys a drink for &#xA3;0.70p. There&#x2019;s no 30p coin in <a href="https://en.wikipedia.org/wiki/Pound_sterling?ref=skerritt.blog">pound sterling</a>, how do you calculate how much change to return?</p><p>For reference, this is the denomination of each coin in the UK:</p><pre><code>1p, 2p, 5p, 10p, 20p, 50p, &#xA3;1
</code></pre><p>The greedy algorithm starts from the highest denomination and works backwards. Our algorithm starts at &#xA3;1. &#xA3;1 is more than 30p, so it can&#x2019;t use it. It does this for 50p. It reaches 20p. 20p &lt; 30p, so it takes 1 20p.</p><p>The algorithm needs to return a change of 10p. It tries 20p again, but 20p &gt; 10p. It next goes to 10p. It chooses 1 10p, and now our return is 0 we stop the algorithm.</p><p>We return 1x20p and 1x10p.</p><p>This algorithm works well in real life. Let&#x2019;s use another example, this time we have the denomination next to how many of that coin is in the machine, <code>(denomination, how many)</code>.</p><pre><code>(1p, 10), (2p, 3), (5p, 1), (10p, 0), (20p, 1p), (50p, 19p), (100p, 16)
</code></pre><p>The algorithm is asked to return a change of 30p again. 100p (&#xA3;1) is no. Same for 50. 20p, we can do that. We pick 1x 20p. We now need to return 10p. 20p has run out, so we move down 1.</p><p>10p has run out, so we move down 1.</p><p>We have 5p, so we choose 1x5p. We now need to return 5p. 5p has run out, so we move down one.</p><p>We choose 1 2p coin. We now need to return 3p. We choose another 2p coin. We now need to return 1p. We move down one.</p><p>We choose 1x 1p coin.</p><p>Our algorithm selected these coins to return as change:</p><pre><code class="language-python"># (value, how many we return as change)
(10, 1)
(5, 1)
(2, 2)
(1, 1)
</code></pre><p>Let&#x2019;s code something. First, we need to define the problem. We&#x2019;ll start with the denominations.</p><pre><code class="language-python">denominations = [1, 2, 5, 10, 20, 50, 100]
# 100p is &#xA3;1
</code></pre><p>Now onto the core function. Given denominations and an amount to give change, we want to return a list of how many times that coin was returned.</p><p>If our <code>denominations</code> list is as above, <code>[6, 3, 0, 0, 0, 0, 0]</code> represents taking 6x1p coins and 3x2p coins, but 0 of all other coins.</p><pre><code class="language-python">denominations = [1, 2, 5, 10, 20, 50, 100]
# 100p is &#xA3;1

def returnChange(change, denominations):
    toGiveBack = [0] * len(denominations)
    for pos, coin in reversed(list(enumerate(denominations))):
</code></pre><p>We create a list, the size of denominations long and fill it with 0&#x2019;s.</p><p>We want to loop backwards, from largest to smallest. <code>Reversed(x)</code> reverses x and lets us loop backwards. Enumerate means &#x201C;for loop through this list, but keep the position in another variable&#x201D;. In our example when we start the loop. <code>coin = 100</code> and <code>pos = 6</code>.</p><p>Our next step is choosing a coin for as long as we can use that coin. If we need to give <code>change = 40</code> we want our algorithm to choose 20, then 20 again until it can no longer use 20. We do this using a for loop.</p><pre><code class="language-python">denominations = [1, 2, 5, 10, 20, 50, 100]
# 100p is &#xA3;1

def returnChange(change, denominations):
    # makes a list size of length denominations filled with 0
    toGiveBack = [0] * len(denominations)

    # goes backwards through denominations list
    # and also keeps track of the counter, pos.
    for pos, coin in enumerate(reversed(denominations)):
        # while we can still use coin, use it until we can&apos;t
        while coin &lt;= change:
</code></pre><p>While the coin can still fit into change, add that coin to our return list, <code>toGiveBack</code> and remove it from change.</p><pre><code class="language-python">denominations = [1, 2, 5, 10, 20, 50, 100]
# 100p is &#xA3;1

def returnChange(change, denominations):
    # makes a list size of length denominations filled with 0
    toGiveBack = [0] * len(denominations)

    # goes backwards through denominations list
    # and also keeps track of the counter, pos.
    for pos, coin in enumerate(reversed(denominations)):
        # while we can still use coin, use it until we can&apos;t
        while coin &lt;= change:
            change = change - coin
            toGiveBack[pos] += 1
    return(toGiveBack)
            
print(returnChange(30, denominations))
# returns [0, 0, 0, 1, 1, 0, 0]
# 1x 10p, 1x 20p
</code></pre><p>The <a href="https://skerritt.blog/big-o/">runtime </a>of this algorithm is dominated by the 2 loops, thus it is O(n2)<em>O</em>(<em>n</em>2).</p><hr><h2 id="is-greedy-optimal-does-greedy-always-work">Is Greedy Optimal? Does Greedy Always Work?</h2><p>It is optimal locally, but sometimes it isn&#x2019;t optimal globally. In the change-giving algorithm, we can force a point at which it isn&#x2019;t optimal globally.</p><p>The algorithm for doing this is:</p><ul><li>Pick 3 denominations of coins. 1p, x, and less than 2x but more than x.</li></ul><p>We&#x2019;ll pick 1, 15, 25.</p><ul><li>Ask for a change of 2 * second denomination (15)</li></ul><p>We&#x2019;ll ask for a change of 30. Now, let&#x2019;s see what our Greedy algorithm does.</p><pre><code>[5, 0, 1]
</code></pre><p>It choses 1x 25p, and 5x 1p. The optimal solution is 2x 15p.</p><p>Our Greedy algorithm failed because it didn&#x2019;t look at 15p. It looked at 25p and thought &#x201C;Yup, that fits. Let&#x2019;s take it.&#x201D;</p><p>It then looked at 15p and thought &#x201C;That doesn&#x2019;t fit, let&#x2019;s move on&#x201D;.</p><p>This is an example of where Greedy Algorithms fail.</p><p>To get around this, you would either have to create currency where this doesn&#x2019;t work or brute-force the solution. Or use Dynamic Programming.</p><hr><h1 id="dijkstra%E2%80%99s-algorithm">Dijkstra&#x2019;s Algorithm</h1><p>Dijkstra&#x2019;s algorithm finds the shortest path from a node to every other node in the graph. In our example, we&#x2019;ll be using a <a href="https://skerritt.blog/graph-theory/">weighted directed graph</a>. Each edge has a direction, and each edge has a weight.</p><p>Dijkstra&#x2019;s algorithm has many uses. It can be very useful within road networks where you need to find the fastest route to a place. We also use the algorithm for:</p><ul><li><a href="https://ieeexplore.ieee.org/document/5381955?ref=skerritt.blog">IP Routing</a></li><li><a href="https://skerritt.blog/a-primer-on-search-algorithms/">A* Algorithm</a></li><li><a href="https://www.sciencedirect.com/science/article/pii/S0020019006003498?ref=skerritt.blog">Telephone networks</a></li></ul><p>The algorithm follows these rules:</p><ol><li>Every time we want to visit a new node, we will choose the node with the smallest known distance.</li><li>Once we&#x2019;ve moved to the node, we check each of its neighbouring nodes. We calculate the distance from the neighbouring nodes to the root nodes by summing the cost of the edges that lead to that new node.</li><li>If the distance to a node is less than a known distance, we&#x2019;ll update the shortest distance.</li></ol><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-107.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="860" height="510" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-107.png 600w, https://skerritt.blog/content/images/2023/06/image-107.png 860w" sizes="(min-width: 720px) 720px"></figure><p>Our first step is to pick the starting node. Let&#x2019;s choose A. All the distances start at infinity, as we don&#x2019;t know their distance until we reach a node that knows the distance.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-108.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="860" height="510" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-108.png 600w, https://skerritt.blog/content/images/2023/06/image-108.png 860w" sizes="(min-width: 720px) 720px"></figure><p>We mark off A on our unvisited nodes list. The distance from A to A is 0. The distance from A to B is 4. The distance from A to C is 2. We updated our distance listing on the right-hand side.</p><p>We pick the smallest edge where the vertex hasn&#x2019;t been chosen. The smallest edge is A -&gt; C, and we haven&#x2019;t chosen C yet. We visit C.</p><p>Notice how we&#x2019;re picking the smallest distance from our current node to a node we haven&#x2019;t visited yet. We&#x2019;re being greedy. Here, the greedy method is the global optimal solution.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-109.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="860" height="510" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-109.png 600w, https://skerritt.blog/content/images/2023/06/image-109.png 860w" sizes="(min-width: 720px) 720px"></figure><p>We can get to B from C. We now need to pick a minimum min(4, 2+1)=3.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-110.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="880" height="510" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-110.png 600w, https://skerritt.blog/content/images/2023/06/image-110.png 880w" sizes="(min-width: 720px) 720px"></figure><p>Since A -&gt; C -&gt; B is smaller than A -&gt; B, we update B with this information. We then add in the distances from the other nodes we can now reach.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-111.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="860" height="510" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-111.png 600w, https://skerritt.blog/content/images/2023/06/image-111.png 860w" sizes="(min-width: 720px) 720px"></figure><p>Our next smallest vertex with a node we haven&#x2019;t visited yet is B, with 3. We visit B.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-112.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="860" height="510" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-112.png 600w, https://skerritt.blog/content/images/2023/06/image-112.png 860w" sizes="(min-width: 720px) 720px"></figure><p>We do the same for B. Then we pick the smallest vertex we haven&#x2019;t visited yet, D.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-113.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="860" height="510" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-113.png 600w, https://skerritt.blog/content/images/2023/06/image-113.png 860w" sizes="(min-width: 720px) 720px"></figure><p>We don&#x2019;t update any of the distances this time. Our last node is then E.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-114.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="860" height="510" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-114.png 600w, https://skerritt.blog/content/images/2023/06/image-114.png 860w" sizes="(min-width: 720px) 720px"></figure><p>There are no updates again. To find the shortest path from A to the other nodes, we walk back through our graph.</p><p>We pick A first, C second, B third. If you need to create the shortest path from A to every other node as a graph, you can run this algorithm using a table on the right-hand side.</p><!--kg-card-begin: html--><table style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; display: table; width: 720px; border-collapse: collapse; border-spacing: 0px; overflow: auto; word-break: keep-all; margin: 25px 0px 32px; font-size: 0.9em; font-family: sans-serif; min-width: 400px; box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 20px; caret-color: rgba(0, 0, 0, 0.88); color: rgba(0, 0, 0, 0.88);"><thead style="box-sizing: border-box;"><tr style="box-sizing: border-box; background-color: rgb(0, 152, 121); color: rgb(255, 255, 255); text-align: left;"><th colspan="3" style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; font-size: 14px; text-align: start; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Dijkstra&apos;s Table</th></tr></thead><tbody style="box-sizing: border-box;"><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Node</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Distance from A</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Previous node</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">A</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">0</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">N/A</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">B</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">3</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">C</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">C</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">2</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">A</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">D</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">5</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">B</td></tr><tr style="box-sizing: border-box; border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">E</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">6</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">B</td></tr></tbody></table><!--kg-card-end: html--><p>Using this table it is easy to draw out the shortest distance from A to every other node in the graph:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-115.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="860" height="510" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-115.png 600w, https://skerritt.blog/content/images/2023/06/image-115.png 860w" sizes="(min-width: 720px) 720px"></figure><h1 id="minimum-spanning-trees-using-prim%E2%80%99s-algorithm">Minimum Spanning Trees Using Prim&#x2019;s Algorithm</h1><p>Prim&#x2019;s algorithm is a greedy algorithm that finds a minimum spanning tree for a weighted undirected graph. It finds the optimal route from every node to every other node in the tree.</p><p>With a small change to Dijkstra&#x2019;s algorithm, we can build a new algorithm - Prim&#x2019;s algorithm!</p><p>We informally describe the algorithm as:</p><ol><li>Create a new tree with a single vertex (chosen randomly)</li><li>Of all the edges not yet in the new tree, find the minimum weighted edge and transfer it to the new tree</li><li>Repeat step 2 until all vertices are in the tree</li></ol><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-116.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1180" height="618" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-116.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-116.png 1000w, https://skerritt.blog/content/images/2023/06/image-116.png 1180w" sizes="(min-width: 720px) 720px"></figure><p>We have this graph.</p><p>Our next step is to pick an arbitrary node.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-117.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1180" height="618" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-117.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-117.png 1000w, https://skerritt.blog/content/images/2023/06/image-117.png 1180w" sizes="(min-width: 720px) 720px"></figure><p>We pick the node A. We then examine all the edges connecting A to other vertices. Prim&#x2019;s algorithm is greedy. That means <strong>it picks the shortest edge that connects to an unvisited vertex.</strong></p><p>In our example, it picks B.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-118.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1180" height="600" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-118.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-118.png 1000w, https://skerritt.blog/content/images/2023/06/image-118.png 1180w" sizes="(min-width: 720px) 720px"></figure><p>We now look at all nodes reachable from A <strong>and</strong> B. This is the distinction between Dijkstra&#x2019;s and Prim&#x2019;s. With Dijkstra&#x2019;s, we&#x2019;re looking for a path from 1 node to a certain other node (nodes that have not been visited). With Prim&#x2019;s, we want the minimum spanning tree.</p><p>We have 3 edges with equal weights of 3. We pick 1 randomly.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-119.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1180" height="618" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-119.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-119.png 1000w, https://skerritt.blog/content/images/2023/06/image-119.png 1180w" sizes="(min-width: 720px) 720px"></figure><p>It is helpful to highlight our graph as we go along because it makes it easier to create the minimum spanning tree.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-120.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1180" height="618" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-120.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-120.png 1000w, https://skerritt.blog/content/images/2023/06/image-120.png 1180w" sizes="(min-width: 720px) 720px"></figure><p>Now we look at all edges of A, B, and C. The shortest edge is C &gt; E with a weight of 1.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-121.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1180" height="618" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-121.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-121.png 1000w, https://skerritt.blog/content/images/2023/06/image-121.png 1180w" sizes="(min-width: 720px) 720px"></figure><p>And we repeat:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-122.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1180" height="618" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-122.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-122.png 1000w, https://skerritt.blog/content/images/2023/06/image-122.png 1180w" sizes="(min-width: 720px) 720px"></figure><p>The edge B &gt; E with a weight of 3 is the smallest edge. However, both vertices are always in our <code>VISITED</code> list. Meaning we do not pick this edge. We instead choose C &gt; F, as we have not visited</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2022/12/Screenshot-2022-12-24-at-09.58.53.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1186" height="624" srcset="https://skerritt.blog/content/images/size/w600/2022/12/Screenshot-2022-12-24-at-09.58.53.png 600w, https://skerritt.blog/content/images/size/w1000/2022/12/Screenshot-2022-12-24-at-09.58.53.png 1000w, https://skerritt.blog/content/images/2022/12/Screenshot-2022-12-24-at-09.58.53.png 1186w" sizes="(min-width: 720px) 720px"></figure><p>The only node left is G, so let&#x2019;s visit it.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2022/12/Screenshot-2022-12-24-at-09.59.25.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1180" height="616" srcset="https://skerritt.blog/content/images/size/w600/2022/12/Screenshot-2022-12-24-at-09.59.25.png 600w, https://skerritt.blog/content/images/size/w1000/2022/12/Screenshot-2022-12-24-at-09.59.25.png 1000w, https://skerritt.blog/content/images/2022/12/Screenshot-2022-12-24-at-09.59.25.png 1180w" sizes="(min-width: 720px) 720px"></figure><p>Note that if the edge weights are distinct, the minimum spanning tree is unique.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2022/12/Screenshot-2022-12-24-at-09.59.54.png" class="kg-image" alt="Greedy Algorithms In Python" loading="lazy" width="1188" height="518" srcset="https://skerritt.blog/content/images/size/w600/2022/12/Screenshot-2022-12-24-at-09.59.54.png 600w, https://skerritt.blog/content/images/size/w1000/2022/12/Screenshot-2022-12-24-at-09.59.54.png 1000w, https://skerritt.blog/content/images/2022/12/Screenshot-2022-12-24-at-09.59.54.png 1188w" sizes="(min-width: 720px) 720px"></figure><p><br>We can add the edge weights to get the minimum spanning tree&#x2019;s total edge weight:</p><p>$$2+3+3+1+6+9=24$$</p><h1 id="fractional-knapsack-problem-using-greedy-algorithm">Fractional Knapsack Problem Using Greedy Algorithm</h1><p>Imagine you are a thief. You break into the house of Judy Holliday - <a href="https://en.wikipedia.org/wiki/23rd_Academy_Awards?ref=skerritt.blog">1951 Oscar winner for Best Actress</a>. Judy is a hoarder of gems. Judy&#x2019;s house is lined to the brim with gems.</p><p>You brought with you a bag - a knapsack if you will. This bag has a weight of 7. You happened to have a listing of &#xA0;Judy&#x2019;s items, from some insurance paper. The items read as:</p><!--kg-card-begin: html--><table style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; display: table; width: 720px; border-collapse: collapse; border-spacing: 0px; overflow: auto; word-break: keep-all; margin: 25px 0px 32px; font-size: 0.9em; font-family: sans-serif; min-width: 400px; box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 20px;"><thead style="box-sizing: border-box;"><tr style="box-sizing: border-box; background-color: rgb(0, 152, 121); color: rgb(255, 255, 255); text-align: left;"><th colspan="3" style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; font-size: 14px; text-align: start; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Judy&apos;s Items</th></tr></thead><tbody style="box-sizing: border-box;"><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Name</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Value</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Weight</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Diamonds</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">16</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">5</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Francium</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">3</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">1</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Sapphire</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">6</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">2</td></tr><tr style="box-sizing: border-box; border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Emerald</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">2</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">1</td></tr></tbody></table><!--kg-card-end: html--><p>The first step to solving the fractional knapsack problem is to calculate \(\frac{value}{weight}\) for each item.</p><!--kg-card-begin: html--><table style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; display: table; width: 720px; border-collapse: collapse; border-spacing: 0px; overflow: auto; word-break: keep-all; margin: 25px 0px 32px; font-size: 0.9em; font-family: sans-serif; min-width: 400px; box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 20px; caret-color: rgba(0, 0, 0, 0.88); color: rgba(0, 0, 0, 0.88);"><thead style="box-sizing: border-box;"><tr style="box-sizing: border-box; background-color: rgb(0, 152, 121); color: rgb(255, 255, 255); text-align: left;"><th colspan="4" style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; font-size: 14px; text-align: start; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;"><br class="Apple-interchange-newline">Judy&apos;s Items</th></tr></thead><tbody style="box-sizing: border-box;"><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Name</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Value</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Weight</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Value / weight</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Diamonds</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">16</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">5</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">3.2</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Francium</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">3</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">1</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">3</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Sapphire</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">6</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">2</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">3</td></tr><tr style="box-sizing: border-box; border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Emerald</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">2</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">1</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">2</td></tr></tbody></table><!--kg-card-end: html--><p>And now we greedily select the largest ones. To do this, we can sort them according to \(\frac{value}{weight}\)</p><p>in descending order. Luckily for us, they are already sorted. The largest one is 3.2.</p><pre><code class="language-python">knapsack value = 16
knapsack total weight = 5 (out of 7)
</code></pre><p>Then we select Francium (I know it&#x2019;s not a gem, but Judy is a bit strange &#x1F609;)</p><pre><code class="language-python">knapsack value = 19
knapsack weight = 6
</code></pre><p>Now, we add Sapphire. But if we add Sapphire, our total weight will come to 8.</p><p>In the fractional knapsack problem, we can cut items up to take fractions of them. We have a weight of 1 left in the bag. Our sapphire has weight 2. We calculate the ratio of:</p><p>$$\frac{weight\;of\;knapsack\;left}{weight\;of\;item}$$</p><p>And then multiply this ratio by the value of the item to get how much value of that item we can take.</p><p>$$\frac{1}{2} * 6 = 3$$</p><pre><code class="language-python">knapsack value = 21
knapsack weight = 7
</code></pre><p>The greedy algorithm can optimally solve the fractional knapsack problem, but it cannot optimally solve the {0, 1} knapsack problem. In this problem instead of taking a fraction of an item, you either take it {1} or you don&#x2019;t {0}. To solve this, you need to use <a href="https://skerritt.blog/dynamic-programming/">Dynamic Programming</a>.</p><p>The <a href="https://skerritt.blog/big-o/">runtime </a>for this algorithm is O(n log n). Calculating \(\frac{value}{weight}\) is O(1). Our main step is sorting from largest \(\frac{value}{weight}\), which takes O(n log n) time.</p><h1 id="greedy-vs-divide-conquer-vs-dynamic-programming">Greedy vs Divide &amp; Conquer vs Dynamic Programming</h1><!--kg-card-begin: html--><table style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; display: table; width: 720px; border-collapse: collapse; border-spacing: 0px; overflow: auto; word-break: keep-all; margin: 25px 0px 32px; font-size: 0.9em; font-family: sans-serif; min-width: 400px; box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 20px;"><thead style="box-sizing: border-box;"><tr style="box-sizing: border-box; background-color: rgb(0, 152, 121); color: rgb(255, 255, 255); text-align: left;"><th colspan="3" style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; font-size: 14px; text-align: start; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Greedy vs Divide &amp; Conquer vs Dynamic Programming</th></tr></thead><tbody style="box-sizing: border-box;"><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;"><strong style="box-sizing: border-box;">Greedy</strong></td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;"><strong style="box-sizing: border-box;">Divide &amp; Conquer</strong></td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;"><strong style="box-sizing: border-box;">Dynamic Programming</strong></td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Optimises by making the best choice at the moment</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Optimises by breaking down a subproblem into simpler versions of itself and using multi-threading &amp; recursion to solve</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Same as Divide and Conquer, but optimises by caching the answers to each subproblem as not to repeat the calculation twice.</td></tr><tr style="box-sizing: border-box; border-bottom-width: thin; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Doesn&apos;t always find the optimal solution, but is very fast</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Always finds the optimal solution, but is slower than Greedy</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Always finds the optimal solution, but could be pointless on small datasets.</td></tr><tr style="box-sizing: border-box; border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: rgb(221, 221, 221); background-color: rgb(243, 243, 243);"><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Requires almost no memory</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Requires some memory to remember recursive calls</td><td style="box-sizing: border-box; padding: 12px 8px; border-bottom: 1px solid var(--border); min-width: 80px; line-height: 1.5; border-top-width: thin !important; border-right-width: thin !important; border-left-width: thin !important; border-top-style: solid !important; border-right-style: solid !important; border-left-style: solid !important; border-top-color: rgb(153, 153, 153) !important; border-right-color: rgb(153, 153, 153) !important; border-left-color: rgb(153, 153, 153) !important;">Requires a lot of memory for memoisation / tabulation</td></tr></tbody></table><!--kg-card-end: html--><p>To learn more about Divide &amp; Conquer and Dynamic Programming, check out these 2 posts I wrote:</p><ul><li><a href="https://skerritt.blog/divide-and-conquer-algorithms/">Divide &amp; Conquer</a></li><li><a href="https://skerritt.blog/dynamic-programming/">Dynamic Programming</a></li></ul><hr><h2 id="conclusion">Conclusion</h2><p>Greedy algorithms are very fast, but may not provide the optimal solution. They are also easier to code than their counterparts.</p>]]></content:encoded></item><item><title><![CDATA[How Does BitTorrent Work? A Plain English Guide]]></title><description><![CDATA[<p>No talk about downloading things on BitTorrent. Or the best clients to do so.</p><p>Just a deep dive into the technical side of it.</p><p>Anyone can read this article. Requires ZERO knowledge of networking or BitTorrent to read this.</p><p>BitTorrent is one of the most common protocols for transferring large</p>]]></description><link>https://skerritt.blog/bit-torrent/</link><guid isPermaLink="false">62de385ec120ec003de76316</guid><category><![CDATA[hacking]]></category><category><![CDATA[programming]]></category><category><![CDATA[Popular]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Sun, 18 Jun 2023 14:32:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1545987796-200677ee1011?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fG5ldHdvcmt8ZW58MHx8fHwxNjU4NzMwNTk0&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1545987796-200677ee1011?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fG5ldHdvcmt8ZW58MHx8fHwxNjU4NzMwNTk0&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="How Does BitTorrent Work? A Plain English Guide"><p>No talk about downloading things on BitTorrent. Or the best clients to do so.</p><p>Just a deep dive into the technical side of it.</p><p>Anyone can read this article. Requires ZERO knowledge of networking or BitTorrent to read this.</p><p>BitTorrent is one of the most common protocols for transferring large files. In February 2013, BitTorrent was responsible for <a href="https://blog.paloaltonetworks.com/app-usage-risk-report-visualization/?ref=skerritt.blog">3.35% of all worldwide bandwidth</a>, more than half of the 6% of total bandwidth dedicated to file sharing.</p><p>Let&#x2019;s dive right in.</p><hr><h1 id="%F0%9F%92%AD-who-created-bittorrent">&#x1F4AD; Who Created BitTorrent?</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-60.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="888" height="617" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-60.png 600w, https://skerritt.blog/content/images/2023/06/image-60.png 888w" sizes="(min-width: 720px) 720px"></figure><p><a href="https://en.wikipedia.org/wiki/Bram_Cohen?ref=skerritt.blog">Bram Cohen</a> invented the BitTorrent protocol in 2001. Cohen wrote the first client implementation in Python.</p><p>Cohen collected free pornography to lure beta testers to use BitTorrent in the summer of 2002.</p><hr><h2 id="%F0%9F%A5%8A-bittorrent-vs-client-server-downloading">&#x1F94A; BitTorrent vs Client-Server Downloading</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-61.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="933" height="784" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-61.png 600w, https://skerritt.blog/content/images/2023/06/image-61.png 933w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/media/bittorrent/2.svg" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy"></figure><p>In traditional downloading, the server uploads the file, and the client downloads the file.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-63.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="720" height="712" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-63.png 600w, https://skerritt.blog/content/images/2023/06/image-63.png 720w" sizes="(min-width: 720px) 720px"></figure><p>For popular files, this isn&#x2019;t very effective.</p><p>500 people downloading the same file will put the server under strain. This strain will cap the upload speed, so clients can not download the file fast.</p><p>Second, the client-server costs a lot of money. The amount we pay increases with how popular a file is.</p><p>Third, it&#x2019;s centralised. Say the system dies, and the file no longer exists - no one can download it.</p><p>BitTorrent aims to solve these problems.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-64.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="612" height="196" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-64.png 600w, https://skerritt.blog/content/images/2023/06/image-64.png 612w"></figure><p>In a peer-to-peer network, every peer is connected to every other peer in the network.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-65.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="420" height="380"></figure><p><em>Semi-centralised peer-to-peer networks</em> possess one or more peers with higher authority than most peers.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-66.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="640" height="460" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-66.png 600w, https://skerritt.blog/content/images/2023/06/image-66.png 640w"></figure><hr><h1 id="%F0%9F%93%91-high-level-overview">&#x1F4D1; High-Level Overview</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-67.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1086" height="612" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-67.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-67.png 1000w, https://skerritt.blog/content/images/2023/06/image-67.png 1086w" sizes="(min-width: 720px) 720px"></figure><p>BitTorrent is a way to share files. It&#x2019;s often used for large files. BitTorrent is an alternative to a single source sharing a file, such as a server. BitTorrent can productively work on lower bandwidth.</p><p>The first release of the BitTorrent client had no search engine and no peer exchange, users who wanted to upload a file had to create a small <em>torrent descriptor file</em> that they would upload to a torrent index site.</p><p>When a user wants to share a file, they seed their file. This user is called a <em>seeder</em>. They upload a torrent descriptor file to an exchange (we&#x2019;ll talk about this later). Anyone who wants to download that file will download this torrent descriptor.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-68.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="550" height="230"></figure><p>We call those who download <em>peers</em>. Their torrent client will connect to a tracker (discussed later) and the tracker will send them a list of IP addresses of other seeds and peers in the swarm. The *swarm *is all PC&#x2019;s related to a certain torrent.</p><p>The torrent descriptor file contains a list of trackers and metadata on the file we&#x2019;re downloading.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-69.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="617" height="313" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-69.png 600w, https://skerritt.blog/content/images/2023/06/image-69.png 617w"></figure><p>A peer will connect to a seed and download parts of the file.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-70.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="674" height="750" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-70.png 600w, https://skerritt.blog/content/images/2023/06/image-70.png 674w"></figure><p>Once the peer completes a download, they could function as a seed. Although, it is possible to function as a seed while also downloading (and is very common).</p><p>Once the seed has shared the file with a peer, that peer will act as a seed. Instead of the client-server model where only 1 server exists to upload the file, in BitTorrent, multiple people can upload the same file.</p><p>BitTorrent splits the file up into chunks called pieces, each of a certain size. Sometimes it&#x2019;s 256KB, sometimes it&#x2019;s 1MB. As each peer receives a piece, they become a seed of that piece for other peers.</p><p>With BitTorrent, we do not have a single source to download from. We could download a few pieces from your home country, then download a few that your home country doesn&#x2019;t own from a faraway country.</p><p>The protocol <a href="https://skerritt.blog/hash-functions/">hashes</a> the pieces to make sure no seed has tampered with the original file. Then stores the hash in the torrent descriptor on the tracker.</p><p>This is how BitTorrent works at a very high level. We will now go into detail. We aim to answer these questions:</p><ul><li>What if a peer only downloads and never uploads?</li><li>Who do we download from, or upload to?</li><li>What is a magnet link?</li><li>What is a torrent descriptor?</li><li>What hashing algorithm is used?</li><li>How does BitTorrent select what pieces to download?</li></ul><p>And much more.</p><hr><h2 id="%F0%9F%93%81-what%E2%80%99s-in-a-torrent-descriptor-file-anyway">&#x1F4C1; What&#x2019;s in a Torrent Descriptor File, Anyway?</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-71.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="998" height="698" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-71.png 600w, https://skerritt.blog/content/images/2023/06/image-71.png 998w" sizes="(min-width: 720px) 720px"></figure><p>It&#x2019;s a dictionary (or hashmap) file.</p><p>The file is described as:</p><ul><li><strong>Announce</strong></li></ul><p>The URL of the tracker. Remember earlier when we contacted the tracker server to find other peers using the same file? We found that tracker by using the announce key in the torrent descriptor file.</p><ul><li><strong>Info</strong></li></ul><p>This maps to a dictionary whose keys depend on whether one or more files are being shared. The keys are:</p><p><strong>Files (child of info, is a list)</strong></p><p><code>Files</code> only exist when multiple files are being shared. <code>Files</code> is a list of dictionaries. Each dictionary corresponds to a file. Each of these dictionaries has 2 keys.</p><p><strong>Length - </strong>the size of the file in bytes.</p><p><strong>Path</strong> - &#xA0;A list of strings corresponding to subdirectory names, the last of which is the actual file name.</p><ul><li><strong>Length</strong></li></ul><p>The size of the file in bytes (only when one file is being shared)</p><ul><li><strong>Name</strong></li></ul><p>Suggested filename. Or the suggested directory name.</p><ul><li><strong>Pieces length</strong></li></ul><p>The number of bytes per piece.</p><p>The piece&#x2019;s length must be a power of two and at least 16KiB.</p><p>This is</p><p><br>$$2^8 \; KiB = 256 \; KiB = 262,144 \; B$$</p><ul><li><strong>Pieces</strong></li></ul><p>A hash list.</p><p>A list of hashes calculated on various chunks of data. We split the data into pieces. Calculate the hashes for those pieces, and stores them in a list.</p><p>BitTorrent uses SHA-1, which returns a 160-bit hash. Pieces will be a string whose length is a multiple of 20 bytes.</p><p>If the torrent contains multiple files, the pieces are formed by concatenating the files in the order they appear in the files directory.</p><p>All pieces in the torrent are the full piece length except for the last piece which may be shorter.</p><p>Now, I can guess what you&#x2019;re thinking.</p><blockquote>&#x201C;SHA-1? What is this? The early 2000s?&#x201D;</blockquote><p>And I agree. <a href="http://bittorrent.org/beps/bep_0052.html?ref=skerritt.blog">BitTorrent is moving from SHA-1 to SHA256.</a></p><p>Still confused? Not to worry! I designed this JSON file that describes what a torrent file looks like.</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">&#x1F42C;</div><div class="kg-callout-text"><strong>Note</strong>: I&#x2019;ve concatenated some things. This makes it easier to read and understand the general layout. I made the numbers up, following the rules of BitTorrent&#x2019;s torrent descriptor.</div></div><pre><code class="language-json">{
    &quot;Announce&quot;: &quot;url of tracker&quot;,
    &quot;Info&quot;: {
        &quot;Files&quot;: [
            {
                &quot;Length&quot;: 16,
                &quot;path&quot;: &quot;/folder/to/path&quot;
            },
            {
                &quot;length&quot;: 193,
                &quot;path&quot;: &quot;/another/folder&quot;
            }
        ]
    },
    &quot;length&quot;: 192,
    &quot;name&quot;:&quot; Ubuntu.iso&quot;,
    &quot;Pieces length&quot;: 262144,
    &quot;Pieces&quot;: [&quot;AAF4C61DDCC5E8A2DABEDE0F3B482CD9AEA9434D&quot;, &quot;CFEA2496442C091FDDD1BA215D62A69EC34E94D0&quot;]
}
</code></pre><hr><h1 id="%F0%9F%A7%80-the-piece-selection-algorithm-of-bittorrent">&#x1F9C0; The Piece Selection Algorithm of BitTorrent</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-72.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="933" height="784" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-72.png 600w, https://skerritt.blog/content/images/2023/06/image-72.png 933w" sizes="(min-width: 720px) 720px"></figure><p>One of the largest questions in BitTorrent is &#x201C;what pieces should I select to download?&#x201D;</p><p>With a traditional client-server model, we download the whole file. But now, we get to pick what pieces to download.</p><p>The idea is to download the pieces that no one else has - the rare pieces. By downloading the rare pieces, we make them less rare by uploading them.</p><h2 id="%F0%9F%8C%86-what-are-sub-pieces-and-the-piece-selection-algorithm">&#x1F306; What Are Sub-Pieces and the Piece Selection Algorithm?</h2><p>BitTorrent uses TCP, a transmission protocol for packets. TCP has a mechanism called <em><a href="https://www.isi.edu/nsnam/DIRECTED_RESEARCH/DR_HYUNAH/D-Research/slow-start-tcp.html?ref=skerritt.blog">slow start</a></em>.</p><p>Slow start is a mechanism which balances the speed of a TCP network connection. It escalates the amount of data transmitted until it finds the network&#x2019;s maximum carrying capacity. <code>cwdn</code> stands for the Congestion Window.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-73.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1327" height="751" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-73.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-73.png 1000w, https://skerritt.blog/content/images/2023/06/image-73.png 1327w" sizes="(min-width: 720px) 720px"></figure><p>TCP does this because if we send 16 connections at once, the server may not be used to the traffic and congestion will happen on the network.</p><p>If we&#x2019;re not regularly sending data, TCP may cap our network connection at a slower speed than normal.</p><p>BitTorrent makes sure to always send data by breaking pieces down into further sub-pieces.</p><p>Each sub-piece is about 16KB in size. The size for a piece is not fixed, but it is somewhere around 1MB.</p><p>The protocol always has some number of requests (five) for a sub-piece pipe-lined. When a new sub-piece is downloaded, the client sends a new request. This helps speed things up.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-74.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1483" height="600" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-74.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-74.png 1000w, https://skerritt.blog/content/images/2023/06/image-74.png 1483w" sizes="(min-width: 720px) 720px"></figure><p>Sub-pieces can be downloaded from other peers.</p><p>Two core policies govern the Piece Selection Algorithm.</p><h3 id="1%EF%B8%8F%E2%83%A3-strict-policy">1&#xFE0F;&#x20E3; Strict Policy</h3><p>Once the BitTorrent client requests a sub-piece of a piece, any remaining sub-pieces of that piece are requested before any sub-pieces from other pieces.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-75.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1000" height="600" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-75.png 600w, https://skerritt.blog/content/images/2023/06/image-75.png 1000w" sizes="(min-width: 720px) 720px"></figure><p>In this image, it makes sense to download all the sub-pieces of this piece first rather than start downloading another piece.</p><h3 id="2%EF%B8%8F%E2%83%A3-rarest-first">2&#xFE0F;&#x20E3; Rarest First</h3><p>The main policy in BitTorrent is to pick the rarest first. We want to download the piece that the fewest other peers own.</p><p>This is so we can make it &#x2018;un-rare&#x2019;. If only one peer has a piece and they go offline, no one will get the complete file.</p><p>A plethora of benefits exists for this policy.</p><p><strong>Growing the seed</strong></p><p>Rarest first makes sure that we download only new pieces from the seed.</p><p>The seed will begin as a bottleneck. The one peer with the file.</p><p>A downloader can see what pieces their peers possess, and the rarest first policy will cause us to fetch the pieces from the seed which have not been uploaded by other peers.</p><p>Let&#x2019;s visualise this.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-76.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1320" height="640" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-76.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-76.png 1000w, https://skerritt.blog/content/images/2023/06/image-76.png 1320w" sizes="(min-width: 720px) 720px"><figcaption>Each peer is connected to every other peer.</figcaption></figure><p>The list of nodes (peers) is interconnected. I cannot draw this as the diagram is unfavourable.</p><p>Each arrow is towards a sub-piece what that peer has downloaded. We downloaded a sub-piece that no one else has other than the seed. This means this sub-piece is rare.</p><p>Our upload rate is higher than that of the seed, so all peers will want to download from us. Also, they would want to download the rarest pieces first, and as we are one of 2 holders of the rarest piece.</p><p>When everyone downloads from us, we can download faster from them. This is the tit-for-tat algorithm (discussed later).</p><p><strong>Increased download speed</strong></p><p>The more peers that hold the piece, the faster the download can happen. This is because we can download sub-pieces from other peers.</p><p><strong>Enable uploading</strong></p><p>A rare piece is most wanted by other peers and getting a rare piece means peers will be interested in uploading from us. As we will see later, the more we upload, the more we can download.</p><p><strong>Most common last</strong></p><p>It is sensible to leave the most common pieces to the end of the download. As many peers hold common pieces, the probability of being able to download them is much larger than that of rare pieces.</p><p><strong>Prevent the rarest piece missing</strong></p><p>When the seed dies, all the different pieces of the file should be distributed somewhere among the remaining peers.</p><h3 id="3%EF%B8%8F%E2%83%A3-random-first-piece">3&#xFE0F;&#x20E3; Random First Piece</h3><p>Once we download, we have nothing to upload. We need the first piece, fast. The rarest first policy is slow. Rare pieces are downloaded slower because we can download its sub-pieces from only a few peers.</p><h3 id="4%EF%B8%8F%E2%83%A3-endgame-mode">4&#xFE0F;&#x20E3; Endgame Mode</h3><p>Sometimes a peer with a slow transfer rate will try to give us a sub-piece. Causing a delay in the download. To prevent this, there is &#x201C;endgame mode&#x201D;.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/endgame.gif" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="220" height="220"></figure><p>Remember the pipe-lining principle? There are always several requests for sub-pieces pending.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-77.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1840" height="700" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-77.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-77.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/06/image-77.png 1600w, https://skerritt.blog/content/images/2023/06/image-77.png 1840w" sizes="(min-width: 720px) 720px"><figcaption>We are downloading from 2 peers, there is 1 other peer we are not downloading from.</figcaption></figure><p>When all the sub-pieces a peer lacks are requested, they broadcast this request to all peers. This helps us get the last chunk of the file.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-78.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1890" height="460" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-78.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-78.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/06/image-78.png 1600w, https://skerritt.blog/content/images/2023/06/image-78.png 1890w" sizes="(min-width: 720px) 720px"></figure><p>If a peer has the missing sub-piece, they will send that back to our computer.</p><p>Once a sub-piece arrives, we send a cancel message telling the other peers to ignore our request.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-79.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1840" height="521" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-79.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-79.png 1000w, https://skerritt.blog/content/images/size/w1600/2023/06/image-79.png 1600w, https://skerritt.blog/content/images/2023/06/image-79.png 1840w" sizes="(min-width: 720px) 720px"><figcaption>We cancel the request to all other peers</figcaption></figure><h1 id="%F0%9F%8C%B1-resource-allocation-using-tit-for-tat">&#x1F331; Resource Allocation Using Tit-For-Tat</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-80.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="827" height="849" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-80.png 600w, https://skerritt.blog/content/images/2023/06/image-80.png 827w" sizes="(min-width: 720px) 720px"></figure><p>No centralised resource allocation in BitTorrent exists. Instead, every peer maximises their download rate.</p><p>A peer will download from whoever they can. To decide who to upload to, they will use a variant of the <a href="https://en.wikipedia.org/wiki/Tit_for_tat?ref=skerritt.blog">&#x201C;tit-for-tat&#x201D;</a> algorithm.</p><p>The tit-for-tat strategy comes from game theory. The essence is:</p><blockquote>&#x201C;Do onto others as they do onto you&#x201D;</blockquote><ol><li>On the first move, cooperate</li><li>On each succeeding move do what your opponent did the previous move</li><li>Be prepared to forgive after carrying out just one act of retaliation</li></ol><hr><h2 id="%F0%9F%8E%90-the-choking-algorithm">&#x1F390; The Choking Algorithm</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-81.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1125" height="801" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-81.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-81.png 1000w, https://skerritt.blog/content/images/2023/06/image-81.png 1125w" sizes="(min-width: 720px) 720px"></figure><p>Choking is a temporary refusal to upload to another peer, but we can still download from them.</p><p>To cooperate peers upload, and to not cooperate they &#x201C;choke&#x201D; the connection to their peers. The principle is to upload to peers who have uploaded to us.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-82.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1598" height="434" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-82.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-82.png 1000w, https://skerritt.blog/content/images/2023/06/image-82.png 1598w" sizes="(min-width: 720px) 720px"></figure><p>We want several bidirectional connections at the same time to achieve <em>Pareto Efficiency</em>.</p><blockquote>We consider an allocation Pareto Efficient if there is no other allocation in which some individual is better off and no individual is worse off.</blockquote><p>Thus the big question, is how to determine which peers to choke and which to unchoke?</p><p>A peer always unchokes a fixed number of its peers (the default is 4).</p><p>Current download rates decide which peers to unchoke. We use a 20-second average to decide this. Because of the use of TCP (slow-start) rapidly choking and unchoking is bad. Thus, this is calculated every 10 seconds.</p><p>If our upload rate is high more peers will allow us to download from them. <strong>This means that we can get a higher download rate if we are a good uploader.</strong> This is the most important feature of the BitTorrent protocol.</p><p>The protocol prohibits many &#x201C;free riders&#x201D; which are peers who only download and don&#x2019;t upload.</p><p>For a peer-to-peer network to be efficient, all peers need to contribute to the network.</p><hr><h1 id="%F0%9F%98%8E-optimistic-unchoking">&#x1F60E; Optimistic Unchoking</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-83.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="743" height="753" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-83.png 600w, https://skerritt.blog/content/images/2023/06/image-83.png 743w" sizes="(min-width: 720px) 720px"></figure><p>BitTorrent also allows an additional unchoked peer, where the download rate criteria aren&#x2019;t used.</p><p>We call this optimistic unchoking. Checking an unused connection isn&#x2019;t better than the one in use.</p><p>We shift the optimistic unchoke every 30 seconds. Enough time for the upload reaches full speed. Same for the upload. If this new connection turns out to be better than one of the existing unchoked connections, it will replace it.</p><p>The optimistic unchoke is randomly selected.</p><p>This also allows peers who do not upload and only download to download the file, even if they refuse to cooperate. Albeit, they will download at a much slower speed.</p><hr><h1 id="%F0%9F%A4%95-anti-snubbing">&#x1F915; Anti-Snubbing</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-84.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1144" height="775" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-84.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-84.png 1000w, https://skerritt.blog/content/images/2023/06/image-84.png 1144w" sizes="(min-width: 720px) 720px"></figure><p>What happens if all peers uploading to another peer decide to choke it? We then have to find new peers, but the optimistic unchoking mechanism only checks one unused connection every 30 seconds. To help the download rate recover more, BitTorrent has <code>snubbing</code>.</p><p>If a client hasn&#x2019;t received anything from a particular peer for 60 seconds, it will presume that it has been &#x2018;snubbed&#x2019;.</p><p>Following the mentality of tit-for-tat, we retaliate and refuse to upload to that peer (except if they become an optimistic unchoke).</p><p>The peer will then increase the number of optimistic unchokes to find new connections quicker.</p><hr><h2 id="%F0%9F%A4%94-what-if-we-upload-only">&#x1F914; What If We Upload Only?</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-85.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="922" height="727" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-85.png 600w, https://skerritt.blog/content/images/2023/06/image-85.png 922w" sizes="(min-width: 720px) 720px"></figure><p>We see that by using the choking algorithm implemented in BitTorrent we favour peers who are kind to us. If I can download fast from them, we allow them to upload fast from me.</p><p>What about no downloads? Then it&#x2019;s impossible to know which peers to unchoke using this choking algorithm. When a download is completed, we use a new choking algorithm.</p><p>This new choking algorithm unchokes peers with the highest upload rate. This ensures that pieces get uploaded faster, and they get replicated faster.</p><p>Peers with good upload rates are also not being served by others.</p><hr><h1 id="%F0%9F%90%9D-what-is-a-tracker">&#x1F41D; What Is a Tracker?</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-86.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="922" height="831" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-86.png 600w, https://skerritt.blog/content/images/2023/06/image-86.png 922w" sizes="(min-width: 720px) 720px"></figure><p>Trackers are special types of servers that help in communication between peers.</p><p>Communication in BitTorrent is important. How do we learn what other peers exist?</p><p>The tracker knows who owns the file, and how much.</p><p>Once a peer-to-peer download has started, communication can continue without a tracker.</p><p>Since the creation of the distributed hash table method for trackerless torrents, BitTorrent trackers are largely redundant.</p><h3 id="%F0%9F%97%BC-public-trackers">&#x1F5FC; Public Trackers</h3><p>These are trackers that anyone can use.</p><p><a href="https://arstechnica.com/tech-policy/2009/11/pirate-bay-kills-its-own-bittorrent-tracker/?ref=skerritt.blog">The Pirate Bay operated one of the most popular public trackers until disabling it in 2009</a>, opting only for magnet links (discussed soon).</p><h3 id="%F0%9F%94%90-private-trackers"><strong>&#x1F510; Private Trackers</strong></h3><p>Private trackers are private. They restrict use by requiring users to register with the site. The method for controlling registration is often an invitation system. To use this tracker we need an invitation.</p><h3 id="%F0%9F%94%A2-multi-tracker-torrents"><strong>&#x1F522; Multi-Tracker Torrents</strong></h3><p>Multi-tracker torrents contain multiple trackers in a single torrent file. This provides redundancy if one tracker fails, the other trackers can continue to maintain the swarm for the torrent.</p><p>With this configuration, it is possible to have multiple unconnected swarms for a single torrent - which is bad. Some users can connect to one specific tracker while being unable to connect to another. This can create a disjoint set which can impede the efficiency of a torrent to transfer the files it describes.</p><h2 id="%F0%9F%A7%B2-magnet-linkstrackerless-torrents">&#x1F9F2; Magnet Links - Trackerless Torrents</h2><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-87.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1034" height="814" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-87.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-87.png 1000w, https://skerritt.blog/content/images/2023/06/image-87.png 1034w" sizes="(min-width: 720px) 720px"></figure><p>Earlier, I talked about how the Pirate Bay got rid of trackers and started using trackerless torrents.</p><p>When we download a torrent, we get a hash of that torrent. To download the torrent without a tracker, we need to find other peers also downloading the torrent. To do this, we need to use a <em>distributed hash table</em>.</p><p>Let&#x2019;s explore Distributed Hash Tables.</p><h1 id="%F0%9F%90%8D-distributed-hash-tables">&#x1F40D; Distributed Hash Tables</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-88.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="998" height="773" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-88.png 600w, https://skerritt.blog/content/images/2023/06/image-88.png 998w" sizes="(min-width: 720px) 720px"></figure><p>Distributed Hash Tables (DHT) give us a dictionary-like interface, but the nodes are distributed across a network. The trick with DHTs is that the node that gets to store a particular key is found by hashing that key.</p><p>In effect, each peer becomes a mini-tracker.</p><p>Each node (client/server implementing the DHT protocol) has a unique identifier known as the &#x201C;node ID&#x201D;. We choose node IDs at random from the same 160-bit space as BitTorrent info hashes.</p><p><a href="https://stackoverflow.com/questions/28348678/what-exactly-is-the-info-hash-in-a-torrent-file/28601408?ref=skerritt.blog">Info hashes </a>are a SHA-1 hash of:</p><ol><li>ITEM: length(size) and path (path with filename)</li><li>Name: The name to search for</li><li>Piece length: The length(size) of a single piece</li><li>Pieces: SHA-1 Hash of EVERY piece of this torrent</li><li>Private: flag for restricted access</li></ol><p>We use a distance metric to compare two node IDs or a node ID and an info hash for &#x201C;closeness&#x201D;.</p><p>Nodes must have a routing table containing the contact information for a few other nodes.</p><p>Nodes know about each other in the DHT. They know many nodes with IDs that are close to their own but few with far-away IDs.</p><p>The distance metric is XOR and is interpreted as an integer.</p><p>$$distance(A, B) = |A \oplus B |$$</p><p>Smaller values are closer.</p><p>When a node wants to find peers for a torrent, they use the distance metric to compare the info hash of the torrent with the IDs of the nodes in its routing table or the ID of one node with the ID of another node.</p><p>Then they contact the nodes in the routing table closest to the info hash and ask them for the contact information of peers downloading the torrent.</p><p>If a contacted node knows about peers for the torrent, they return the peer contact information with the response. Otherwise, the contacted node must respond with the contact information of the nodes in its routing table closet to the info hash of the torrent.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-89.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1533" height="540" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-89.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-89.png 1000w, https://skerritt.blog/content/images/2023/06/image-89.png 1533w" sizes="(min-width: 720px) 720px"></figure><p>The original node queries nodes that are closer to the target info hash until it cannot find any closer nodes. After the node exhausts the search, the client then inserts the peer contact information for itself onto the responding nodes with IDs closest to the info hash of the torrent. In the future, other nodes can easily find us.</p><p>The return value for a query for peers includes an opaque value known as the &#x201C;token.&#x201D; For a node to announce that its controlling peer is downloading a torrent, it must present the token received from the same queried node in a recent query for peers.</p><p>When a node attempts to &#x201C;announce&#x201D; a torrent, the queried node checks the token against the querying node&#x2019;s IP address. This is to prevent malicious hosts from signing up other hosts for torrents.</p><p>The querying node returns the token to the same node that they receive the token from. We must accept tokens for a reasonable amount of time after they have been distributed. The BitTorrent implementation uses the SHA-1 hash of the IP address concatenated onto a secret that changes every five minutes and tokens up to ten minutes old are accepted.</p><hr><h1 id="%F0%9F%93%8C-routing-table">&#x1F4CC; Routing Table</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-90.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1142" height="960" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-90.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-90.png 1000w, https://skerritt.blog/content/images/2023/06/image-90.png 1142w" sizes="(min-width: 720px) 720px"></figure><p>Every node maintains a routing table of known good nodes. We use the routing table starting points for queries in the DHT. We return nodes from the routing table in response to queries from other nodes.</p><p>Not all nodes we learn about are equal. Some are &#x201C;good&#x201D; and some are not. Many nodes using the DHT can send queries and receive responses, but cannot respond to queries from other nodes. Each node&#x2019;s routing table must contain only known good nodes.</p><p>A good node is a node has responded to one of our queries within the last 15 minutes. A node is also good if it has ever responded to our queries and has sent us a query within the last 15 minutes. After 15 minutes of inactivity, a node becomes questionable. Nodes become bad when they fail to respond to multiple queries in a row. Nodes that we see are good are given priority over nodes with an unknown status.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-91.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1057" height="907" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-91.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-91.png 1000w, https://skerritt.blog/content/images/2023/06/image-91.png 1057w" sizes="(min-width: 720px) 720px"></figure><p>The routing table covers the entire node ID space from 0 to 2160. We subdivide the routing table into &#x201C;buckets&#x201D; that each cover a portion of the space.</p><p>An empty table has one bucket with an ID space range of min=0, max=2160.</p><p>An empty table has only one bucket so any node must fit within it. Each bucket can only hold K nodes, currently eight, before becoming &#x201C;full.&#x201D;</p><p>When a bucket is full of known good nodes, we may add no more nodes unless our node ID falls within the range of the bucket. The bucket is replaced by two buckets each with half of the old bucket. Nodes from the old bucket are distributed among the new buckets.</p><p>For a new table with only one bucket, we always split the full bucket into two new buckets covering the ranges 0..2<sup>159</sup> and 2<sup>159</sup>..2<sup>160</sup>.</p><p>When the bucket is full of good nodes, we simply discard the new node. When nodes in the bucket become bad (if they do) we replace them with a new node.</p><p>When nodes are considered questionable and haven&#x2019;t been since, in the last 15 minutes, the least recently seen node is pinged. The node either responds or doesn&#x2019;t respond. A response means we move to the next node. We do this until we find a node that fails to respond. If we don&#x2019;t find any, then the bucket is considered good.</p><p>When we do find one, we try one more time before discarding the node and replacing them with a new good node.</p><p>Each bucket should maintain a &#x201C;last changed&#x201D; property to show how &#x201C;fresh&#x201D; the contents are.</p><p>When a node in a bucket is pinged and responds, or a node is added to a bucket or a node is replaced with another node, the bucket&#x2019;s last changed property is updated.</p><p>Buckets are refreshed if the last changed property has not been updated in the last 15 minutes.</p><hr><h1 id="%F0%9F%A4%BA-attacks-on-bittorrent">&#x1F93A; Attacks on BitTorrent</h1><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-92.png" class="kg-image" alt="How Does BitTorrent Work? A Plain English Guide" loading="lazy" width="1042" height="709" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-92.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-92.png 1000w, https://skerritt.blog/content/images/2023/06/image-92.png 1042w" sizes="(min-width: 720px) 720px"></figure><p>Few attacks on the BitTorrent network exist. Everything is public. Our IP address, what we&#x2019;re downloading - everything. Why attack an open network?</p><p>Why attack a completely open network?</p><p><a href="https://www.exploit-db.com/?ref=skerritt.blog">Only 7 entries are listed on Exploit-DB</a> - a database of known exploits against a service. And most of them relate to specific clients.</p><p>The principal attack on the BitTorrent network is to stop piracy. We&#x2019;ve gone this far without talking about piracy, but it is often synonymous with BitTorrent.</p><p>The main attack on BitTorrent is <em>Torrent Poisoning</em>.</p><h3 id="torrent-poisoning">Torrent Poisoning</h3><p>This attack aims to get the IP addresses of peers pirating content or to poison the content in some way.</p><p>Madonna&#x2019;s American Life album release is an example of content poisoning. Before the release, tracks were released of similar length and file size. <a href="https://www.youtube.com/watch?v=XU5xC00m-gA&amp;ref=skerritt.blog">The tracks featured a clip of Madonna saying</a>:</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/XU5xC00m-gA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen title="Madonna - What the F*ck Do You Think You&apos;re Doing?"></iframe></figure><blockquote>&#x201C;What the fuck do you think you&#x2019;re doing?&#x201D;</blockquote><p>Followed by a few minutes of silence.</p><p>Here are some methods of poisoning a torrent.</p><h3 id="index-poisoning"><strong>Index Poisoning</strong></h3><p>The index allows users to locate the IP addresses of peers with the desired content. This method of attack makes searching for peers difficult.</p><p>The attacker inserts a large amount of invalid information into the index to prevent users from finding the correct information.</p><p>The idea is to slow down the download, by having the peer try to download pieces from an invalid peer.</p><h3 id="decoy-insertion">Decoy Insertion</h3><p>They insert corrupted versions of a file into the network.</p><p>Imagine 500 copies of a file and only 2 of them being the real file, this deters pirates from finding the real file.</p><p>Most websites with lists of torrents a voting system. This deters this attack, as the top of searches is filled with non-corrupted files However, most websites with lists of torrents a voting</p><p>This deters this attack, as the top of searches is filled with non-corrupted files.</p><p>In GameDevTycoon, the file was released before the initial upload to piracy sites. Unbeknownst to pirates, the file was corrupted. Winning the game is impossible in the pirated version. Everything else was perfect.</p><h3 id="%F0%9F%A7%99%F0%9F%8F%BC%E2%80%8D%E2%99%82%EF%B8%8F-defence-against-the-dark-bittorrent-attack">&#x1F9D9;&#x1F3FC;&#x200D;&#x2642;&#xFE0F; Defence Against the Dark BitTorrent Attack</h3><p>Most popular torrents are released by individuals or groups who built up a rapport over many years. On private trackers, individuals can be pointed to. Poisoned torrents are quickly labelled and the poster can be banned.</p><p>Or, on public trackers, downloading torrents made by trusted groups is preferable. After all, would you prefer to download Ubuntu from the Ubuntu team, or the user xxx-HACKER-ELITE-GHOST-PROTOCOL-xxx?</p><p>On public trackers, if a torrent is poisoned the torrent is reported and removed.</p><p>The simplest way to defend against a BitTorrent attack is to use an IP address not associated with you. Whether this is through a VPN or some other service.</p><h1 id="%F0%9F%91%8B%F0%9F%8F%BB-conclusion">&#x1F44B;&#x1F3FB; Conclusion</h1><p>Here are the things we&#x2019;ve learnt:</p><ul><li>What a Torrent Descriptor file is</li><li>How BitTorrent chooses peers</li><li>How BitTorrent chooses pieces</li><li>Tit-For-Tat algorithms</li><li>Trackers</li><li>Attacks on the BitTorrent network</li></ul><p>Here are some things you may choose to do:</p><ul><li><a href="https://allenkim67.github.io/programming/2016/05/04/how-to-make-your-own-bittorrent-client.html?ref=skerritt.blog">Build your own BitTorrent client</a></li><li><a href="https://www.bittorrent.org/beps/bep_0000.html?ref=skerritt.blog">Explore BitTorrent&#x2019;s proposals (BEPs) to learn more about how it works, and what&#x2019;s next for the algorithm</a></li><li><a href="https://www.bittorrent.org/beps/bep_0003.html?ref=skerritt.blog">Read the official BitTorrent specification</a></li></ul>]]></content:encoded></item><item><title><![CDATA[How to Share a Secret (Diffie-Hellman-Merkle)]]></title><description><![CDATA[<p>Diffie-Hellman-Merkle is a way to share a secret key with someone (or something) without actually sending them the key. Before we look into how we share keys let&#x2019;s first look into what keys are and why we would want to invent a method to share keys without giving</p>]]></description><link>https://skerritt.blog/diffie-hellman-merkle/</link><guid isPermaLink="false">63a6cf01389f0a003dab16c3</guid><category><![CDATA[Algorithms]]></category><category><![CDATA[Popular]]></category><dc:creator><![CDATA[Autumn Skerritt]]></dc:creator><pubDate>Sun, 18 Jun 2023 10:39:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1671780208057-50b5c72cd7b8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDI0fHx8fHx8Mnx8MTY3MTg3NjIwNQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1671780208057-50b5c72cd7b8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8YWxsfDI0fHx8fHx8Mnx8MTY3MTg3NjIwNQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="How to Share a Secret (Diffie-Hellman-Merkle)"><p>Diffie-Hellman-Merkle is a way to share a secret key with someone (or something) without actually sending them the key. Before we look into how we share keys let&#x2019;s first look into what keys are and why we would want to invent a method to share keys without giving the other person the key.</p><hr><p>Your front door is usually locked by a key. This key unlocks &amp; locks your front door. You have one key which you use to unlock and lock things.</p><p>Only people with the key or a copy of the key can unlock the door. Now, imagine you&#x2019;re going to be on holiday Friday, Saturday, Sunday in Bali. You want to invite your friend around to look after your cat &#x1F63A; while you&#x2019;re on the beautiful beaches &#x1F3D6;&#xFE0F;.</p><p>Your only friend is unfortunately on holiday Wednesday, Thursday and Friday. They get back right as you leave for holiday. You can&#x2019;t be there to physically give them the key, but hiding the key under a rock outside your door seems insecure. Anyone could lift up that rock and find the key, but you just want your friend to have the key.</p><p>This is where Diffie-Hellman comes in. Well, with Diffie-Hellman you&#x2019;re not exchanging physical keys but rather digital keys. Let&#x2019;s explore some basic cryptography to understand why digital key exchange sucks just as much as real life key exchange.</p><hr><p>Julius Caesar used a cipher to send messages that no one else could read other than the intended recipient. Mainly because no one could read back in 100 BC, and those that could wouldn&#x2019;t understand a random string of letters. That&#x2019;s the whole point of cryptography. To create ways to communicate without third parties understanding the message. This cipher is Caesar*&#x2018;s Cipher*. Given an alphabet and a key (the key is an integer between 1 and 25), shift all of the alphabet letters by key.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://skerritt.blog/content/images/2023/06/image-51.png" class="kg-image" alt="How to Share a Secret (Diffie-Hellman-Merkle)" loading="lazy" width="600" height="251" srcset="https://skerritt.blog/content/images/2023/06/image-51.png 600w"><figcaption><a href="https://www.geeksforgeeks.org/caesar-cipher/?ref=skerritt.blog">Caeser&apos;s Cipher shift of 3</a> /</figcaption></figure><p>With a shift of 3, as seen in the image above, A becomes D, B becomes E and so on until it wraps around with X = A. The original message is called the *plaintext *and the encrypted message is called the <em>ciphertext</em>.</p><p>The easiest way to perform Caesar&#x2019;s Cipher is to turn all of the letters into numbers, a = 1, b = 2, c = 3 and so on.</p><p>To encrypt, E, you calculate this for every letter (where s is the shift):</p><p>$$ E_{s}(letter) = (letter + shift)$$</p><p>To decrypt Caesar&#x2019;s cipher, D, you calculate this for every letter:</p><p>$$D_{s}(letter) = (letter - shift)$$</p><p>Something important to note is that this version of the cipher doesn&#x2019;t support wraparound (for brevity).</p><p>As you can tell, it&#x2019;s not very secure. With 25 total shifts you just have to shift the text 25 times until you find the decrypted code, this is called a brute force attack. You take the encrypted text and shift it all 25 times until you find the decrypted text. But let&#x2019;s imagine for a second that this was a hard cipher - that brute force isn&#x2019;t feasible.</p><p>The shift is the key to Caesar&#x2019;s cipher. But the problem still persists, how do you tell your friend you&#x2019;re using a shift of 9? Any and all forms of communication can be listened in on. It doesn&#x2019;t matter if you&#x2019;re writing a letter or going to a hidden forest in Switzerland 30 miles from the nearest town. If you communicate the key, it can be listened in on.</p><p>How do you tell your friend you&#x2019;re using a shift of 9, for example? You have to communicate it to them somehow. Any and all forms of communication can be listened in on - whether that&#x2019;s writing a letter or going to a hidden forest in Switzerland 30 miles from the nearest town and telling your friend.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-52.png" class="kg-image" alt="How to Share a Secret (Diffie-Hellman-Merkle)" loading="lazy" width="1060" height="620" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-52.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-52.png 1000w, https://skerritt.blog/content/images/2023/06/image-52.png 1060w" sizes="(min-width: 720px) 720px"></figure><p>The problem becomes even more apparent when you realise that communicating parties over the internet usually have no prior knowledge about each other and are thousands of miles apart. This is where the magic of Diffie-Hellman-Merkle key exchange comes in.</p><hr><h2 id="diffie-hellman-merkle">Diffie-Hellman-Merkle</h2><p>Diffie-Hellman is a way to securely exchange keys in public. It was conceptualised by Ralph Merkle, and named After Whitfield Diffie and Martin Hellman. I have chosen to include Merkle&#x2019;s name as the title because he put in just as much work as Diffie-Hellman and his name never appears when this algorithm is talked about.</p><p><a href="https://www.google.com/patents/US4200770?ref=skerritt.blog">U.S. Patent 4,200,770</a>, from 1977, is now expired and describes the now-public-domain algorithm. It credits Hellman, Diffie, and Merkle as inventors.</p><p>Let&#x2019;s go through how this algorithm works.</p><ol><li>Pick two numbers, G and N.</li></ol><p>For this algorithm, we will also walk through the colour mixing method for explaining how it works.</p><p>Alice and Bob publicly agree to use a modulus p = 23 and g = 5 (which is a primitive root modulo 23, explained later). Modulus is just the remainder of the division. Note: this example comes from <a href="https://www.wikiwand.com/en/Diffie%E2%80%93Hellman_key_exchange?ref=skerritt.blog">Wikipedia</a>.</p><p>It&#x2019;s hard to describe the painting method in text, so if you want to know about this method I suggest watching this video:</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-53.png" class="kg-image" alt="How to Share a Secret (Diffie-Hellman-Merkle)" loading="lazy" width="500" height="665"></figure><p>We&#x2019;ll colour G yellow. We have 2 copies of G (yellow) as seen above.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-54.png" class="kg-image" alt="How to Share a Secret (Diffie-Hellman-Merkle)" loading="lazy" width="1014" height="860" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-54.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-54.png 1000w, https://skerritt.blog/content/images/2023/06/image-54.png 1014w" sizes="(min-width: 720px) 720px"></figure><p>When Alice and Bob agree on these numbers, Eve knows they are using these numbers.</p><p>2. Alice needs to calculate a private key.</p><p>She does this by picking a secret number (a). She computes <strong>G<sup>a</sup> mod p </strong>and sends that result to Bob.</p><p>Alice chooses a secret, random integer a = 4.</p><p>Alice computes <strong>A = 5<sup>4</sup> mod 23 = 4 </strong>and sends the number 4 to Bob.</p><p>She colours this private key reddish-brown.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-55.png" class="kg-image" alt="How to Share a Secret (Diffie-Hellman-Merkle)" loading="lazy" width="1220" height="860" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-55.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-55.png 1000w, https://skerritt.blog/content/images/2023/06/image-55.png 1220w" sizes="(min-width: 720px) 720px"></figure><p>Eve doesn&#x2019;t know Alice&#x2019;s secret number is 4, only that the result of this equation is 4. It&#x2019;s not feasible for Eve to calculate what Alice&#x2019;s secret number is from the resultant of this equation.</p><p>3. Bob makes his own private key. Its colour is dark green.</p><p>He calculates this by picking a secret number (b) and computes <strong>g<sup>b</sup> mod p</strong>. He then sends the result to Alice. Bob creates a random private key, for this example we&#x2019;ll use 3.</p><p>Then Bob calculates <strong>b = 5<sup>3</sup> mod 23 = 10</strong> and sends 10 to Alice.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-56.png" class="kg-image" alt="How to Share a Secret (Diffie-Hellman-Merkle)" loading="lazy" width="1440" height="860" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-56.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-56.png 1000w, https://skerritt.blog/content/images/2023/06/image-56.png 1440w" sizes="(min-width: 720px) 720px"></figure><p>4. Now Bob takes the number Alice sent him and computes <strong>b<sup>a</sup> mod p.</strong></p><p>In the colour analogy, this is taking Alice&#x2019;s paint colour and adding it to Bob&#x2019;s paint colour.</p><p>Bob computes <strong>s = 4<sup>3</sup> mod 23 = 18.</strong></p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-57.png" class="kg-image" alt="How to Share a Secret (Diffie-Hellman-Merkle)" loading="lazy" width="1460" height="860" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-57.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-57.png 1000w, https://skerritt.blog/content/images/2023/06/image-57.png 1460w" sizes="(min-width: 720px) 720px"></figure><p>Bob doesn&#x2019;t send this to Alice.</p><p>5. Alice computes <strong>a<sup>b</sup> mod p</strong>.</p><p>In the paint analogy, this is Alice adding Bob&#x2019;s paint (that Bob sent her) to her painting.</p><p>Alice calculates <strong>s = 10<sup>4</sup> mod 23 = 18</strong></p><p>The magic is that Alice and Bob now have the same number or the same paint colour.</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-58.png" class="kg-image" alt="How to Share a Secret (Diffie-Hellman-Merkle)" loading="lazy" width="1480" height="860" srcset="https://skerritt.blog/content/images/size/w600/2023/06/image-58.png 600w, https://skerritt.blog/content/images/size/w1000/2023/06/image-58.png 1000w, https://skerritt.blog/content/images/2023/06/image-58.png 1480w" sizes="(min-width: 720px) 720px"></figure><p>Let&#x2019;s discuss in detail the mathematics behind this cool algorithm.</p><p>Explanation of maths</p><p>Diffie-Hellman-Merkle works because of a cool modulus exponent principle. First, let&#x2019;s explain what modulus is before we try to understand this principle.</p><h3 id="modular-arithmetic">Modular Arithmetic</h3><p>Imagine a finite range of numbers, for example, 1 to 12. These numbers are arranged in a circle, much like a clock (modular arithmetic is sometimes called clock arithmetic because of this).</p><figure class="kg-card kg-image-card"><img src="https://skerritt.blog/content/images/2023/06/image-59.png" class="kg-image" alt="How to Share a Secret (Diffie-Hellman-Merkle)" loading="lazy" width="512" height="512"></figure><p>Count 13 around this clock. You get to 12 and then you need to count 1 more - so you go back to 1. Modular arithmetic is still defined as the remainder of division, however, it can also be defined (and is more commonly defined) as a clock.</p><p>Functions using modular arithmetic tend to perform erratically, which in turn sometimes makes them one-way functions. Let&#x2019;s see this with an example by taking a regular function and seeing how it works when it becomes a modular arithmetic function.</p><p>$$3^x$$</p><p>When we insert 2 into this function, we get <strong>3<sup>2</sup> = 6</strong>. Insert 3 and we get <strong>3<sup>3</sup> = 9</strong>.</p><p>This function is easy to reverse. If we&#x2019;re given 9, we can tell that the function had an input of 3, because <strong>3</strong><sup><strong>3</strong></sup><strong> = 9</strong>.</p><p>However, with modular arithmetic added, it doesn&#x2019;t behave sensibly.</p><p>Imagine we had this formula:</p><p>$$3^{x} mod 7$$</p><p>How would you find out what x is? You can&#x2019;t put the mod on the other side, because there isn&#x2019;t really an inverse of modular arithmetic. What about guessing? Let&#x2019;s input 5:</p><p>$$3^{5} mod 7$$</p><p>Okay, that was too big. You might want to go lower, maybe 4 or 3 but actually this is the wrong direction. When x is 6, it is equal to 1.</p><p>In normal arithmetic, we can test numbers and get a feel for whether we are getting warmer or colder, but this isn&#x2019;t the case with modular arithmetic.</p><p>Often the easiest way to reverse modular arithmetic is to compile a table for all values of x until the right answer is found. Although this may work for smaller numbers, it is computationally infeasible to do for much larger numbers. This is often why modular arithmetic is known as a one-way function.</p><p>If I gave you a number such as 5787 and told you to find the function for it, it would be infeasible. In fact, if I gave you the ability to input any number into the function it would still be hard. It took me a mere few seconds to make this function, but it&#x2019;ll take you hours or maybe even days to work out what x is.</p><p>Diffie-Hellman-Merkle is a one-way function. While it is relatively easy to carry out this function, it is computationally infeasible to do the reverse of the function and find out what the keys are. Although, it is possible to reverse an RSA encryption if you know some numbers such as N.</p><h1 id="primitive-root">Primitive root</h1><p>The primitive root of a prime number, p, is a number, a, such that all numbers:</p><p>$$a \; mod \; p, a^2 mod p, a^3 \; mod \; p, a^4 \; mod \; p, ...$$</p><p>are different. There is a formula for counting what the indices are, but I think it&#x2019;s far more intuitive to acknowledge &#x201C;the second one is to the power of 2, the third one is to the power of 3&#x201D; and so on.</p><p>Let&apos;s see an example where $p = 7$. Let&apos;s set $a_1 = 2$ and $a_2 = 3$.</p><p>$$2^0 = 1 ( mod \ 7) = 1$$ &#xA0;</p><p>$$2^1 = 2 ( mod \ 7) = 2$$ &#xA0;</p><p>$$2^2 = 4 ( mod \ 7) = 4$$ &#xA0;</p><p>$$2^3 = 8 ( mod \ 7) = 1$$</p><p>Uh oh! 20 is the same as 23. This means that 2 is not a primitive root of 7. Let&#x2019;s try again with 3.</p><p>$$3^0 = 1 ( mod \ 7) = 1$$ &#xA0;</p><p>$$3^1 = 3 (mod \ 7) = 3$$ &#xA0;</p><p>$$3^2 = 9 (mod \ 7) = 2$$ &#xA0;</p><p>$$3^3 = 27 (mod \ 7) = 6$$ &#xA0;</p><p>$$3^4 = 81 ( mod \ 7) = 4$$ &#xA0;</p><p>$$3^5 = 243 ( mod \ 7) = 5$$ &#xA0;</p><p>$$3^6 = 1 (mod \ 7) = 1$$</p><p>Now let&#x2019;s try a = 3.</p><p>$$3^0 = 1$$ </p><p>$$3^1 = 3$$ </p><p>$$3^2 = 2$$ </p><p>$$3^3 = 6$$ </p><p>$$3^4 = 4$$ </p><p>$$3^5 = 5$$ </p><p>$$3^6 = 1$$</p><p>Now we&#x2019;ve got a cycle in these powers.</p><p>36 = 1, and 30 = 1. This is because we are using modulus it repeats into this cycle, so we can stop now. Unlike before where we reached 23 and it cycled, it&apos;s okay if it cycles here because for any prime number, p, and any number, a, such that \(a \ne 0 \ mod \ p\) and \(a \ne 1 \; mod \; p\) the consecutive powers of \(a\) may cover no more than p - 1 values modulo p. That is, we go from \(1, ..., p - 1\). When p is 7, the consecutive powers cover up to 6.</p><h1 id="discrete-logarithms">Discrete logarithms</h1><p>$$a^b = c \; mod \; n$$</p><p>Such an equation means some numbers you can write it differently as:</p><p>$$log_a c = b \; mod \; n$$</p><p>Logarithms are the inverse of exponents, we&#x2019;ve just inversed the sum here.</p><p>Now it&#x2019;s a well-defined function, we can say in discrete terms that \(log_3 5 = 5 \ (mod \ 7)\) (looking at the table above).</p><p>if you use a non-primitive root number it becomes easier, as we have a smaller number of outcomes (because it repeats earlier), as seen below.</p><p>$$2^0 = 1 (mod \ 7) = 1$$ &#xA0;</p><p>$$2^1 = 2 ( mod \ 7) = 2$$ &#xA0;</p><p>$$2^2 = 4 ( mod \ 7) = 4$$ &#xA0;</p><p>$$2^3 = 8 ( mod \ 7) = 1$$</p><p>By using a primitive root, we get a much larger outcome, making it harder.</p><p>$$3^0 = 1 ( mod \ 7) = 1$$ &#xA0;</p><p>$$3^1 = 3 (mod \ 7) = 3$$ &#xA0;</p><p>$$3^2 = 9 ( mod \ 7) = 2$$ &#xA0;</p><p>$$3^3 = 27 ( mod \ 7) = 6$$ &#xA0;</p><p>$$3^4 = 81 ( mod \ 7) = 4$$ &#xA0;</p><p>$$3^5 = 243 ( mod \ 7) = 5$$ &#xA0;</p><p>$$3^7 = 1 ( mod \ 7) = 1$$</p><p>It is relatively easy to calculate exponentials modulo a prime, that is a, l, p calculate <strong>a<sup>i</sup> mod p</strong>.</p><p>Exponentiation is a cheap operation. you can do it even for very large numbers while logarithm is a much more difficult function to calculate for large numbers.</p><p>To calculate exponentiation, you give number 2 and you respond to me what the answer is. that&#x2019;s exponentiation, going from left to right.</p><p>$$3^0 = 1$$ &#xA0;</p><p>$$3^1 = 3$$ &#xA0;</p><p>$$3^2 = 2$$ &#xA0;</p><p>$$3^3 = 6$$ &#xA0;</p><p>$$3^4 = 4$$ &#xA0;</p><p>$$3^5 = 5$$</p><p>Logarithm is how to go back, from right to left. Logarithms are much harder than exponentiation.</p><hr><h1 id="maths-implemented">Maths implemented</h1><p>Let&#x2019;s go back to seeing how Diffie-Hellman worked, but this time with a lot more knowledge of how mathematics works.</p><p>We have 2 people, Alice and Bob. Each of them has to agree in advance on some prime number q (publicly known number) and its primitive root a (publicly known).</p><p>1. Alice selects a random integer \(x_a &lt; q\) and keeps it in secret </p><p>2. B selects a random integer \(x_b &lt; q\) and keeps it in secret </p><p>3. Alice calculates the function left to right (exponentiation) </p><p>$$3^0 = 2$$ &#xA0;</p><p>$$3^1 = 3$$ &#xA0;</p><p>$$3^2 = 2$$ &#xA0;</p><p>$$3^3 = 6$$ &#xA0;</p><p>$$3^4 = 4$$ &#xA0;</p><p>$$3^5 = 5$$<br></p><p>and they choose one of the exponents, chosen randomly and kept in secret. Now Alice does \(y_a = a^{x a} mod q\) and sends it to Bob.</p><p>This example isn&#x2019;t very impressive, and sometimes <strong>3<sup>5</sup> = 5</strong> but for much larger numbers most things change everything, this is almost RSA encryption (the idea is the same, but it&#x2019;s not quite the same as this is key exchange, not encryption).</p><p>Bob then does the same as Alice. Both Alice and Bob are now capable of calculating the shared key.</p><p>Alice calculates \(k = (y_b)^{x_a} \; mod \; q\)</p><p>Bob calculates \(k = (y_a)^{x_b} \; mod \; q\)</p><p>Now they have the same numbers, k is the common secret key.</p><p>$$(\alpha ^ {x_b})^{x_a} = (\alpha ^ {x_a})^{x_b}$$</p><p>This equation above is what makes it all work. The formulae are the same, but different. You get Alice to do one side of the formula, Bob does another side and they end up with the same number.</p><p>This really is the equation that puts it all together. Most of this blog post led up to this equation.</p><p><code>a</code> and <code>b</code> are secret, and without these numbers, there is no easy way to repeat these computations because in to do it you need to know the secrets.</p><p>The above formula shows that the two methods are exactly equal. If you do the left equation, you get the same result as the right equation.<br></p><h1 id="conclusion">Conclusion</h1><p>Diffie-Hellman-Merkle is a fascinating way of sharing a secret over an unsecured communications medium, by not sharing it at all over that medium.</p>]]></content:encoded></item></channel></rss>