Jekyll2024-01-15T19:19:41+00:00https://kylereddoch.me/feed.xmlKyle’s Tech KornerKyle's Tech Korner is a place to for tech news, tips, tricks and more. Set back, enjoy a cup of coffee and learn about tech.New Branding: Welcome to Kyle’s Tech Korner!2024-01-15T00:00:00+00:002024-01-15T00:00:00+00:00https://kylereddoch.me/2024/01/15/new-brand-kyles-tech-korner<p>Hello friends! Kyle here. You may be thinking, another rebrand?! I know, sorry. I have decided that software development and coding in general isn’t my main passion. Of course it will always be a passion of mine and I am not leaving that community but it will be taking on more of a hobby role moving forward.</p>
<h2 id="the-rebrand">The Rebrand</h2>
<p>As I was giving thought to what my true passion was, I got the opportunity to become an IT Manager for a local company. As I was working at the company, getting into the Managed Services industry and really digging myself into the ins and outs of the IT, Cybersecurity, RMM, and Networking community, rekindled my passion.</p>
<p>Since then I have also change my major in college to IT from Computer Science to further that passion and continue to garner my knowledge in that area. So, as a compliment of that, I felt that as I kept writing, I need to rebrand my site to keep the theme so as to not confuse people. I didn’t want to start writing articles, reviews, etc. about things related to IT on a site that was geared towards Software Engineering/Development. So, with that, I decided to rebrand.</p>
<h2 id="kyles-tech-korner">Kyle’s Tech Korner</h2>
<p>Welcome to Kyle’s Tech Korner! Kyle’s Tech Korner will be dedicated to articles, reviews, experiences, etc. around tech, cybersecurity, infosec, managed services, and more. As I continue my career through this industry, I want to have a place to not only write about my experiences but also hope to help others.</p>
<p>I know that this rebrand will cause some of my followers to leave since the focus of my site has changed. I hope that some of you will continue to find my articles, etc. appealing to stay. If not though, I understand. If you have friends that will benefit from my new shift, I would appreciate if you let them know about my site.</p>
<p>Thanks, Kyle</p>Kyle ReddochHello friends! Kyle here. You may be thinking, another rebrand?! I know, sorry. I have decided that software development and coding in general isn’t my main passion. Of course it will always be a passion of mine and I am not leaving that community but it will be taking on more of a hobby role moving forward.How to Add a Mastodon Share Button to Your Website2023-02-20T00:00:00+00:002023-02-20T00:00:00+00:00https://kylereddoch.me/2023/02/20/creating-mastodon-share-button<p>Ever since Elon took over the helm of Twitter and causing quite an uproar, people have been flocking to Mastodon as their new social media platform. Mastdodon isn’t showing any signs of going anywhere anytime soon, so it will be here for a long time. With this change, people have been looking for a way that would allow their readers to share their content to Mastodon, myself included.</p>
<p>Mastodon, though, is different than Twitter in that it is a decentralized network. This means that the mechanics of creating a share button is a <em>little</em> bit more complicated than just using a URL (you need to know <em>where</em> to send the user).</p>
<p>In this post, I will show you how I created a Mastodon share button for this website using a little bit of HTML and Javascript.</p>
<h2 id="the-challenge">The Challenge</h2>
<p>Per the <a href="https://docs.joinmastodon.org/methods/statuses/">Mastodon documentation</a>, we need to send the button to the following URL <code class="language-plaintext highlighter-rouge">/share</code> url on the users Mastodon instance, but we don’t know what instance the user is on; this could be anything from <code class="language-plaintext highlighter-rouge">iosdev.space</code> to <code class="language-plaintext highlighter-rouge">mastodon.social</code>. At this time, there is no way to automatically determine the users instance, at least not that I know of.</p>
<p>We can accomplish this by using a little bit of Javascript (with a <code class="language-plaintext highlighter-rouge">click</code> event) to prompt the user for their instance (via Javascript’s <code class="language-plaintext highlighter-rouge">prompt()</code>) and then open a window onto the share page that prepopulates both the post title and URL of your article (these are editable by the user to whatever they what to post).</p>
<h3 id="the-javascript">The Javascript</h3>
<p>For the Javascript, we will need to create a function that will prompt the user for their instance and then open a new window with the share URL. We will also need to add a <code class="language-plaintext highlighter-rouge">click</code> event to the button that will call this function.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Generate a share link for the user's Mastodon domain */</span>
<span class="kd">function</span> <span class="nx">MastodonShare</span><span class="p">(</span><span class="nx">e</span><span class="p">){</span>
<span class="c1">// Gather the source text and URL</span>
<span class="nx">src</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">getAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">data-src</span><span class="dl">"</span><span class="p">);</span>
<span class="c1">// Gather the Mastodon domain</span>
<span class="nx">domain</span> <span class="o">=</span> <span class="nx">prompt</span><span class="p">(</span><span class="dl">"</span><span class="s2">Enter your Mastodon domain</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">mastodon.social</span><span class="dl">"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">domain</span> <span class="o">==</span> <span class="dl">""</span> <span class="o">||</span> <span class="nx">domain</span> <span class="o">==</span> <span class="kc">null</span><span class="p">){</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Build the URL</span>
<span class="nx">url</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">domain</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">/share?text=</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">src</span><span class="p">;</span>
<span class="c1">// Open a window on the share page</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="dl">'</span><span class="s1">_blank</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<div align="center"><a class="button" href="https://donate.stripe.com/3cs7voeE46LX07e7ss" target="_blank">Support this site with a cup of coffee</a></div>
<h3 id="the-html">The HTML</h3>
<p>For the HTML, we will need to create a button that will call the function when clicked (the <code class="language-plaintext highlighter-rouge">onclick</code> attribute). We will also need to add a <code class="language-plaintext highlighter-rouge">data-src</code> attribute that will contain the text that we want to share. Here is what mine looks like, yours might look a little different.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><a</span> <span class="na">onclick=</span><span class="s">"MastodonShare(this);"</span>
<span class="na">data-src=</span><span class="s">"{{ page.title }}&amp;url={{ page.url | absolute_url }}"</span> <span class="na">title=</span><span class="s">"{{ site.data.social.language.str_share_on }} Mastodon"</span><span class="nt">></span>
<span class="nt"><i</span> <span class="na">class=</span><span class="s">"fab fa-mastodon fa-2x"</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">></i></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">></span>{{ site.data.social.language.str_share_on | default: "Share on" }} Mastodon<span class="nt"></span></span>
<span class="nt"></a></span>
</code></pre></div></div>
<p>Okay, this is if you your share button is an icon or link, but what if you have them as an image? Well, you can do that too. It is a <em>little</em> different, but I will show you how to do that as well.</p>
<h3 id="the-image-button">The Image Button</h3>
<p>As with the icon button, we will use the <code class="language-plaintext highlighter-rouge">data-src</code> attribute to store the text that we want to share. Your image button can look something like this, but just came sure that is has the <code class="language-plaintext highlighter-rouge">data-src</code> attribute and whatever <code class="language-plaintext highlighter-rouge">class</code> you use in the same you use in the <code class="language-plaintext highlighter-rouge">javascript</code> below.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><img</span> <span class="na">class=</span><span class="s">"mastodon-share"</span>
<span class="na">style=</span><span class="s">"display: none"</span>
<span class="na">loading=</span><span class="s">"lazy"</span>
<span class="na">src=</span><span class="s">"/images/social-icons/mastodon_share.jpg"</span>
<span class="na">alt=</span><span class="s">"Share this post on Mastodon"</span>
<span class="na">title=</span><span class="s">"Share this post on Mastodon"</span>
<span class="na">data-src=</span><span class="s">"{{ page.title }}&amp;url={{ page.url | absolute_url }}"</span>
<span class="nt">></span>
</code></pre></div></div>
<p>Because the image share functionality is reliant on Javascript, it would be best to hide the image by defaulut that way if users do not have Javascript enabled, they will not see the image. To do this, we will add a <code class="language-plaintext highlighter-rouge">style</code> attribute to the image and set it to <code class="language-plaintext highlighter-rouge">display: none;</code>.</p>
<p>This way the image is revealed with Javescript using the following code (which also includes the <code class="language-plaintext highlighter-rouge">click</code> event listener):</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Call this on document.ready() */</span>
<span class="kd">function</span> <span class="nx">enableMastodonShare</span><span class="p">(){</span>
<span class="kd">var</span> <span class="nx">eles</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="dl">'</span><span class="s1">mastodon-share</span><span class="dl">'</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o"><</span><span class="nx">eles</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
<span class="nx">eles</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">click</span><span class="dl">'</span><span class="p">,</span> <span class="nx">MastodonShare</span><span class="p">);</span>
<span class="cm">/* Make visible by removing the original display: none */</span>
<span class="nx">eles</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">style</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<div align="center"><a class="button" href="https://donate.stripe.com/3cs7voeE46LX07e7ss" target="_blank">Support this site with a cup of coffee</a></div>
<h2 id="the-result">The Result</h2>
<p>After clicking your share button, the user will be prompted with a prompt to enter with Mastodon instance.</p>
<div class="row">
<div class="column">
<img class="single" src="/assets/img/instance-popup.png" alt="instance-popup.png" />
</div>
</div>
<p>Once they have entered thier instance and hit okay, a new window will open with the share page prepopulated with the title and URL of the post on their instance.</p>
<div class="row">
<div class="column">
<img class="single" src="/assets/img/mastodon-share-box.png" alt="mastodon-share-box.png" />
</div>
</div>
<h2 id="conclusion">Conclusion</h2>
<p>I hope this post has helped you create your own Mastodon share button. If you have any questions, feel free to reach out to me on Mastodon at <a href="https://iosdev.space/@kylewritescode">@kylewritescode</a>.</p>
<p>If you have enjoyed this post, please consider supporting the site.</p>Kyle ReddochEver since Elon took over the helm of Twitter and causing quite an uproar, people have been flocking to Mastodon as their new social media platform. Mastdodon isn’t showing any signs of going anywhere anytime soon, so it will be here for a long time. With this change, people have been looking for a way that would allow their readers to share their content to Mastodon, myself included.Using an Alias for Your Mastodon Account with Jekyll and GitHub Pages2023-02-15T00:00:00+00:002023-02-15T00:00:00+00:00https://kylereddoch.me/2023/02/15/using-alias-for-mastodon-account-jekyll-github-pages<p>If you are like myself and many other Birdsite users of past, you have began flocking to <a href="https://joinmastodon.org" target="_blank">Mastodon</a> and making yourself a home there. Mastodon although is different than most mainstream social media platforms. It is a federated network, meaning that there are many different instances of Mastodon that are all connected to each other. This means that you can <a href="https://joinmastodon.org/servers" target="_blank">choose which instance</a> you want to use and you can even <a href="https://docs.joinmastodon.org/user/run-your-own/" target="_blank">create your own instance</a> if you want to. This is great because it means that you can choose an instance that you like and that you feel comfortable with.</p>
<p>So you decided to choose an instance you liked and created an account. In my case, I chose to use <a href="https://iosdev.space" target="_blank">iosdev.space</a> as my instance and my username is kylewritescode. Therefore, my full Mastodon account is <a href="https://iosdev.space/@kylewritescode" target="_blank">@kylewritescode@iosdev.space</a>.</p>
<p>What if you wanted to add a little more personalization to your username? What if you wanted to use a domain you already have without having to struggle with hosting an entire Mastodon server? With this personalization, it means that no matter what instance you use, or what instance you decide to use in the future, you will always be able to share the same username and have it pointed to your account.</p>
<p>Here is how I did it using GitHub Pages. Although, this can be done using any hosting service that allows you to create a .named folder.</p>
<h2 id="using-webfinger">Using WebFinger</h2>
<p>Mastodon uses <a href="https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/" target="_blank">ActivityPub</a> to communication with “actors” and those actors are found using WebFinger, a way to attach information to a specific email address or other online resource. So, to get my personalized username to work, I just needed to create a WebFinger spec on my domain.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><yourinstaceaddress>/.well-known/webfinger?resource=acct:<yourusername>@<yourinstaceaddress>
</code></pre></div></div>
<p>So, if I wanted to get information about my account on iosdev.space, I would go to:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://iosdev.space/.well-known/webfinger?resource=acct:kylewritescode@iosdev.space
</code></pre></div></div>
<p>That means, when I go to that endpoint, I get a JSON response that looks like this:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"subject"</span><span class="p">:</span><span class="w"> </span><span class="s2">"acct:kylewritescode@iosdev.space"</span><span class="p">,</span><span class="w">
</span><span class="nl">"aliases"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"https://iosdev.space/@kylewritescode"</span><span class="p">,</span><span class="w">
</span><span class="s2">"https://iosdev.space/users/kylewritescode"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"links"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"rel"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://webfinger.net/rel/profile-page"</span><span class="p">,</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"text/html"</span><span class="p">,</span><span class="w">
</span><span class="nl">"href"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://iosdev.space/@kylewritescode"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"rel"</span><span class="p">:</span><span class="w"> </span><span class="s2">"self"</span><span class="p">,</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"application/activity+json"</span><span class="p">,</span><span class="w">
</span><span class="nl">"href"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://iosdev.space/users/kylewritescode"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"rel"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://ostatus.org/schema/1.0/subscribe"</span><span class="p">,</span><span class="w">
</span><span class="nl">"template"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://iosdev.space/authorize_interaction?uri={uri}"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Now all I need to do is put that JSON reponse in the same directory and file and that’s it!</p>
<div align="center"><a class="button" href="https://donate.stripe.com/3cs7voeE46LX07e7ss" target="_blank">Support this site with a cup of coffee</a></div>
<h2 id="creating-the-webfinger-spec-with-jekyll">Creating the WebFinger Spec with Jekyll</h2>
<p>My blog runs on <code class="language-plaintext highlighter-rouge">Jekyll</code> and is hosted on <code class="language-plaintext highlighter-rouge">GitHub Pages</code>. To have your Mastodon alias work with your domain tied to your Jekyll site, you need to follow a few steps:</p>
<ol>
<li>Create a folder in the root of your site called <code class="language-plaintext highlighter-rouge">.well-known</code></li>
<li>Inside that folder, create a file called <code class="language-plaintext highlighter-rouge">webfinger</code>, with no file extension</li>
<li>Insided that file, paste the JSON response from the WebFinger endpoint</li>
<li>In your <code class="language-plaintext highlighter-rouge">_config.yml</code> file, add the following: (This allows Jekyll to include the <code class="language-plaintext highlighter-rouge">.well-known</code> folder in the build process.)</li>
</ol>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">include</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">/.well-known"</span> <span class="pi">]</span>
</code></pre></div></div>
<p>That’s it! Just push your changes to GitHub and your alias will be ready to go. You can test it by going to <code class="language-plaintext highlighter-rouge">anything@yourdomain.whatever</code> on Mastodon and it will redirect you to your account.</p>
<p>Check it out! Here is my alias working on Mastodon:</p>
<div class="row">
<div class="column">
<img class="single" src="/assets/img/mastodon-alias-example.png" alt="mastodon-alias-example.png" />
</div>
</div>
<hr />
<h4 id="references">References</h4>
<p>During my research, I found out about this method thanks to the article by <a href="https://blog.maartenballiauw.be" target="_blank">Maarten Balliauw</a> called <a href="https://blog.maartenballiauw.be/post/2022/11/05/mastodon-own-donain-without-hosting-server.html" target="_blank">Mastodon on your own domain without hosting a server</a>.</p>Kyle ReddochIf you are like myself and many other Birdsite users of past, you have began flocking to Mastodon and making yourself a home there. Mastodon although is different than most mainstream social media platforms. It is a federated network, meaning that there are many different instances of Mastodon that are all connected to each other. This means that you can choose which instance you want to use and you can even create your own instance if you want to. This is great because it means that you can choose an instance that you like and that you feel comfortable with.Adding Mastodon Comments to a Jekyll Blog2023-02-13T00:00:00+00:002023-02-13T00:00:00+00:00https://kylereddoch.me/2023/02/13/adding-mastodon-comments-jekyll-blog<p>With the crashing and burning happening at Twitter, I have made the personal decision to leave the platform that I have loved and enjoyed for the past 14 years. I have enjoyed great conversations, connections, and even learned in that timespan. but seeing how things are spawning out of control, I have decided to move to a platform that I have been wanting to learn for a while now. I have decided to move to <a href="https://iosdev.space/@kylewritescode">Mastodon</a>.</p>
<p>Now I have had a Mastodon account ever since 2016 but haven’t used it until just a few days ago. Once I started using it, I realized that I really like the platform. It is a great alternative to Twitter and I am excited to learn more about it. I was off to the races. I have since learned quite a bit about the platform and have been enjoying it. I have also been enjoying the conversations I have been having with people on the platform. Somehow, I have been having more meaningful conversations on Mastodon than I have on Twitter. I have also moved (more about that in another post) to <a href="https://iosdev.space">iosdev.space</a> which is a great instance to be on if you’rer interested in iOS or Swift development.</p>
<p>Well, since I have falling in love with Mastodon, it has gotten me intrigued with the idea of the <a href="https://en.wikipedia.org/wiki/Fediverse">Fediverse</a> as a whole and I am 100% going down the rabbit hole. I am finding decentralized alternatives to centralized apps and services that I use on a daily basis. Because of that, I have decided to move my blogs commenting system away from disqus and over to Mastodon. The migrating is now complete and I am excited to share how I did it.</p>
<h2 id="modifications-made-to-jekyll">Modifications made to Jekyll</h2>
<p>There were two modifications that needed to be made to my Jekyll instance to get this working. First, I had to create a new html file. I named it <code class="language-plaintext highlighter-rouge">fediverse_comments.html</code> (you can name it whatever you like) and placed it in the <code class="language-plaintext highlighter-rouge">_includes</code> folder. Here’s what that file looks like.</p>
<h3 id="_includesfediverse_commentshtml">_includes\fediverse_comments.html</h3>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"comments"</span><span class="nt">></span>
<span class="nt"><h2></span>Comments<span class="nt"></h2></span>
<span class="nt"><p></span>You can use your [Mastodon](https://joinmastodon.org) account to comment on this article by replying to the associated Mastodon <span class="nt"><a</span> <span class="na">class=</span><span class="s">"link"</span> <span class="na">href=</span><span class="s">"https://{{ page.comments.host }}/@{{ page.comments.username }}/{{ page.comments.id }}"</span><span class="nt">></span>post<span class="nt"></a></span>.<span class="nt"></p></span>
<span class="nt"><p></span>
<span class="nt"><a</span> <span class="na">class=</span><span class="s">"button"</span> <span class="na">href=</span><span class="s">"https://{{ page.comments.host }}/@{{ page.comments.username }}/{{ page.comments.id }}"</span><span class="nt">></span>Reply via Mastodon><span class="nt"></a></span>
<span class="nt"></p></span>
<span class="nt"><p</span> <span class="na">id=</span><span class="s">"mastodon-comments-list"</span><span class="nt">><a</span> <span class="na">class=</span><span class="s">"button"</span> <span class="na">id=</span><span class="s">"load-comment"</span><span class="nt">></span>Load comments from Mastodon<span class="nt"></a></p></span>
<span class="nt"><noscript><p></span>You need JavaScript to view the comments.<span class="nt"></p></noscript></span>
<span class="nt"><script </span><span class="na">src=</span><span class="s">"/assets/js/purify.min.js"</span><span class="nt">></script></span>
<span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></span>
<span class="kd">function</span> <span class="nx">escapeHtml</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">unsafe</span>
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/&/g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&amp;</span><span class="dl">"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/</g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&lt;</span><span class="dl">"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/>/g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&gt;</span><span class="dl">"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/"/g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&quot;</span><span class="dl">"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/'/g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&#039;</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">load-comment</span><span class="dl">"</span><span class="p">).</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">"</span><span class="s2">click</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">load-comment</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Loading</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">fetch</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://{{ page.comments.host }}/api/v1/statuses/{{ page.comments.id }}/context</span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="nx">data</span><span class="p">[</span><span class="dl">'</span><span class="s1">descendants</span><span class="dl">'</span><span class="p">]</span> <span class="o">&&</span>
<span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">data</span><span class="p">[</span><span class="dl">'</span><span class="s1">descendants</span><span class="dl">'</span><span class="p">])</span> <span class="o">&&</span>
<span class="nx">data</span><span class="p">[</span><span class="dl">'</span><span class="s1">descendants</span><span class="dl">'</span><span class="p">].</span><span class="nx">length</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">mastodon-comments-list</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="dl">""</span><span class="p">;</span>
<span class="nx">data</span><span class="p">[</span><span class="dl">'</span><span class="s1">descendants</span><span class="dl">'</span><span class="p">].</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">reply</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span> <span class="o">=</span> <span class="nx">escapeHtml</span><span class="p">(</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span><span class="p">);</span>
<span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">emojis</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">emoji</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span> <span class="o">=</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s2">`:</span><span class="p">${</span><span class="nx">emoji</span><span class="p">.</span><span class="nx">shortcode</span><span class="p">}</span><span class="s2">:`</span><span class="p">,</span>
<span class="s2">`<img src="</span><span class="p">${</span><span class="nx">escapeHtml</span><span class="p">(</span><span class="nx">emoji</span><span class="p">.</span><span class="nx">static_url</span><span class="p">)}</span><span class="s2">" alt="Emoji </span><span class="p">${</span><span class="nx">emoji</span><span class="p">.</span><span class="nx">shortcode</span><span class="p">}</span><span class="s2">" height="20" width="20" />`</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">mastodonComment</span> <span class="o">=</span>
<span class="s2">`<div class="mastodon-comment">
<div class="avatar">
<img src="</span><span class="p">${</span><span class="nx">escapeHtml</span><span class="p">(</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">avatar_static</span><span class="p">)}</span><span class="s2">" height=60 width=60 alt="">
</div>
<div class="content">
<div class="author">
<a href="</span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">url</span><span class="p">}</span><span class="s2">" rel="nofollow">
<span></span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span><span class="p">}</span><span class="s2"></span>
<span class="disabled"></span><span class="p">${</span><span class="nx">escapeHtml</span><span class="p">(</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">acct</span><span class="p">)}</span><span class="s2"></span>
</a>
<a class="date" href="</span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">uri</span><span class="p">}</span><span class="s2">" rel="nofollow">
</span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">created_at</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">)}</span><span class="s2">
</a>
</div>
<div class="mastodon-comment-content"></span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">content</span><span class="p">}</span><span class="s2"></div>
</div>
</div>`</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">mastodon-comments-list</span><span class="dl">'</span><span class="p">).</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">DOMPurify</span><span class="p">.</span><span class="nx">sanitize</span><span class="p">(</span><span class="nx">mastodonComment</span><span class="p">,</span> <span class="p">{</span><span class="dl">'</span><span class="s1">RETURN_DOM_FRAGMENT</span><span class="dl">'</span><span class="p">:</span> <span class="kc">true</span><span class="p">}));</span>
<span class="p">});</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">mastodon-comments-list</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="dl">"</span><span class="s2"><p>Not comments found</p></span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="nt"></script></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p>Second I needed to change the exising <code class="language-plaintext highlighter-rouge">post.html</code> file locaed in the <code class="language-plaintext highlighter-rouge">_layouts</code> folder. I added the following code which will tell Jekyll to use the <code class="language-plaintext highlighter-rouge">fediverse_comments.html</code> file when it is rendering the post if the <code class="language-plaintext highlighter-rouge">comments</code> variable is set in the front matter of the post (more on that in a bit).</p>
<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{%</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">comments</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>social/fediverse_comments.html<span class="w"> </span><span class="p">%}</span>
<span class="p">{%-</span><span class="kr">endif</span><span class="w"> </span><span class="p">%}</span>
</code></pre></div></div>
<p>You can add this code anywhere in the <code class="language-plaintext highlighter-rouge">post.html</code> file. I added it at the bottom of the file since I wanted the comments to be at the bottom of the post.</p>
<p>Here is what my <code class="language-plaintext highlighter-rouge">post.html</code> file looks like.</p>
<h3 id="_layoutsposthtml">_layouts\post.html</h3>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><article</span> <span class="err">{%</span> <span class="na">if</span> <span class="na">page.feature-img</span> <span class="na">or</span> <span class="na">page.color</span> <span class="err">%}</span> <span class="na">class=</span><span class="s">"feature-image"</span> <span class="err">{%</span> <span class="na">endif</span> <span class="err">%}</span> <span class="na">itemscope</span> <span class="na">itemtype=</span><span class="s">"http://schema.org/BlogPosting"</span><span class="nt">></span>
<span class="nt"><header</span> <span class="na">id=</span><span class="s">"main"</span> <span class="na">style=</span><span class="s">""</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"title-padder"</span><span class="nt">></span>
{% if page.hide_title %}
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"feature-image-padding"</span><span class="nt">></div></span>
{% else %}
<span class="nt"><h1</span> <span class="na">id=</span><span class="s">"{{ page.title | cgi_escape }}"</span> <span class="na">class=</span><span class="s">"title"</span><span class="nt">></span>{{ page.title }}<span class="nt"></h1></span>
{% include blog/post_info.html author=page.author date=page.date %}
{% endif %}
<span class="nt"></div></span>
<span class="nt"></header></span>
<span class="nt"><section</span> <span class="na">class=</span><span class="s">"post-content"</span><span class="nt">></span>
{% if page.bootstrap %}
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"bootstrap-iso"</span><span class="nt">></span>
{% endif %}
{{ content }}
{% if page.bootstrap %}
<span class="nt"></div></span>
{% endif %}
<span class="nt"></section></span>
<span class="c"><!-- Tag list --></span>
{% capture tag_list %}{{ page.tags | join: "|"}}{% endcapture %}
{% include default/tags_list.html tags=tag_list %}
<span class="c"><!-- Social media shares --></span>
{% include social/share_buttons.html %}
<span class="nt"></article></span>
<span class="c"><!-- Fediverse --></span>
{%- if page.comments -%}
{%- include social/fediverse_comments.html -%}
{%- endif -%}
<span class="c"><!--Utterances--></span>
{% if site.comments.utterances.repo and site.comments.utterances.issue-term %} {% include social/utterances.html %} {% endif %}
<span class="c"><!-- Cusdis --></span>
{% if site.comments.cusdis_app_id or site.cusdis_app_id %}{% include social/cusdis.html %}{% endif %}
<span class="c"><!-- Disqus --></span>
{% if site.comments.disqus_shortname or site.theme_settings.disqus_shortname or site.disqus_shortname %}
{% include social/disqus.html %}{% endif %}
<span class="c"><!-- Post navigation --></span>
{% if site.post_navigation or site.theme_settings.post_navigation %}
{% include blog/post_nav.html %}
{% endif %}
<span class="c"><!-- To change color of links in the page --></span>
<span class="nt"><style></span>
<span class="nt">header</span><span class="nf">#main</span> <span class="p">{</span>
<span class="nl">background-size</span><span class="p">:</span> <span class="n">cover</span><span class="p">;</span>
<span class="nl">background-repeat</span><span class="p">:</span> <span class="nb">no-repeat</span><span class="p">;</span>
<span class="nl">background-position</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">{</span><span class="err">%</span> <span class="err">if</span> <span class="err">page.color</span> <span class="err">%</span><span class="p">}</span>
<span class="p">{</span><span class="err">%</span> <span class="err">comment</span> <span class="err">%</span><span class="p">}</span><span class="nc">.feature-image</span> <span class="nt">a</span> <span class="p">{</span> <span class="nl">color</span><span class="p">:</span> <span class="err">{{</span> <span class="n">page</span><span class="p">.</span><span class="n">color</span> <span class="p">}</span><span class="err">}</span> <span class="o">!</span><span class="nt">important</span><span class="o">;</span> <span class="err">}</span><span class="p">{</span><span class="err">%</span> <span class="err">endcomment</span> <span class="err">%</span><span class="p">}</span>
<span class="p">{</span><span class="err">%</span> <span class="err">comment</span> <span class="err">%</span><span class="p">}</span><span class="nt">div</span><span class="nf">#post-nav</span> <span class="nt">a</span> <span class="p">{</span> <span class="nl">color</span><span class="p">:</span> <span class="err">{{</span> <span class="n">page</span><span class="p">.</span><span class="n">color</span> <span class="p">}</span><span class="err">}</span> <span class="o">!</span><span class="nt">important</span><span class="o">;</span> <span class="err">}</span><span class="p">{</span><span class="err">%</span> <span class="err">endcomment</span> <span class="err">%</span><span class="p">}</span>
<span class="p">{</span><span class="err">%</span> <span class="err">comment</span> <span class="err">%</span><span class="p">}</span><span class="nt">footer</span> <span class="nt">a</span> <span class="p">{</span> <span class="nl">color</span><span class="p">:</span> <span class="err">{{</span> <span class="n">page</span><span class="p">.</span><span class="n">color</span> <span class="p">}</span><span class="err">}</span> <span class="o">!</span><span class="nt">important</span><span class="o">;</span> <span class="err">}</span><span class="p">{</span><span class="err">%</span> <span class="err">endcomment</span> <span class="err">%</span><span class="p">}</span>
<span class="p">{</span><span class="err">%</span> <span class="err">comment</span> <span class="err">%</span><span class="p">}</span><span class="nc">.site-header</span> <span class="nt">nav</span> <span class="nt">a</span><span class="nd">:hover</span> <span class="p">{</span> <span class="nl">color</span><span class="p">:</span> <span class="err">{{</span> <span class="n">page</span><span class="p">.</span><span class="n">color</span> <span class="p">}</span><span class="err">}</span> <span class="o">!</span><span class="nt">important</span><span class="o">;</span> <span class="err">}</span><span class="p">{</span><span class="err">%</span> <span class="err">endcomment</span> <span class="err">%</span><span class="p">}</span>
<span class="nt">header</span><span class="nf">#main</span> <span class="p">{</span>
<span class="nl">background-color</span><span class="p">:</span> <span class="err">{{</span> <span class="n">page</span><span class="p">.</span><span class="n">color</span> <span class="p">}</span><span class="err">}</span> <span class="o">!</span><span class="nt">important</span><span class="o">;</span>
<span class="nt">background-image</span><span class="o">:</span> <span class="nt">url</span><span class="o">(</span><span class="s2">'{{ site.color_image | relative_url }}'</span><span class="o">);</span>
<span class="err">}</span>
<span class="p">{</span><span class="err">%</span> <span class="err">endif</span> <span class="err">%</span><span class="p">}</span>
<span class="p">{</span><span class="err">%</span> <span class="err">if</span> <span class="err">page.feature-img</span> <span class="err">%</span><span class="p">}</span>
<span class="nt">header</span><span class="nf">#main</span> <span class="p">{</span> <span class="nl">background-image</span><span class="p">:</span> <span class="sx">url('{{ page.feature-img | relative_url }}')</span><span class="p">;</span> <span class="p">}</span>
<span class="p">{</span><span class="err">%</span> <span class="err">endif</span> <span class="err">%</span><span class="p">}</span>
<span class="nt"></style></span>
{% endif %}
</code></pre></div></div>
<h2 id="enabling-comments-on-a-post">Enabling Comments on a Post</h2>
<p>Now that we have the code in place to render the comments we need to tell Jekyll to render the comments on a post. To do this we need to add the <code class="language-plaintext highlighter-rouge">comments</code> variable to the front matter of the post.</p>
<p>Before that though, you will need to first create a post on Mastodon for the article (meaning you will have to come back and edit the post with the id) that you will be creating comments for. This is because the comments are tied to the post on Mastodon. After that post is created you will need to get the ID of the post. You can get the ID by going to the post on Mastodon and looking at the URL. The ID will be the number at the end of the URL. For example, if the URL is <code class="language-plaintext highlighter-rouge">https://iosdev.space/@kylewritescode/106000000000000000</code> the ID is <code class="language-plaintext highlighter-rouge">106000000000000000</code>. Once you have the ID you can add the <code class="language-plaintext highlighter-rouge">comments</code> variable to the front matter of the post.</p>
<p>Here is an example of what the front matter of a post would look like.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>comments:
host: iosdev.space
username: kylewritescode
id: 109325166591243911
</code></pre></div></div>
<p>Host is the domain of the instance you want to pull comments from (the instance you’re on). Username is the username of the user who created the post (you). Id is the id of the post. You can find the id of the post by going to the post on the instance and looking at the url. The id is the number at the end of the url.</p>
<p>And that is all! You should now have comments on your Jekyll site using Mastodon. If you have any questions or comments feel free to reach out to me on Mastodon <a href="https://iosdev.space/@kylewritescode">@kylewritecode@iosdev.space</a>.</p>Kyle ReddochWith the crashing and burning happening at Twitter, I have made the personal decision to leave the platform that I have loved and enjoyed for the past 14 years. I have enjoyed great conversations, connections, and even learned in that timespan. but seeing how things are spawning out of control, I have decided to move to a platform that I have been wanting to learn for a while now. I have decided to move to Mastodon.Tutorial: Create a Simple npx Business Card2022-09-26T00:30:00+00:002022-09-26T00:30:00+00:00https://kylereddoch.me/2022/09/26/create-a-simple-npx-business-card<p>One of the most common things we Software Engineers do is tinker with code. That is what I have done with Javascript and NodeJS.</p>
<p>I created a CLI tool that uses a custom npm package to display a nerdy style business card. Here is how I created it:</p>
<h4 id="using-javascript-for-clis-is-easy">Using javascript for CLIs is easy</h4>
<ul>
<li>the npm build, publish, and share cycle is so easy</li>
<li><code class="language-plaintext highlighter-rouge">npx</code> allows you to execute without installation</li>
<li>the npm ecosystem is ripe for CLIs</li>
</ul>
<h2 id="npx-business-card">npx business card</h2>
<p><strong>We will be using the command line to during part of this tutorial.</strong></p>
<p>Let’s start creating this business card. The final output might look something like this: (I have customized this quite a bit to my needs)</p>
<p><img src="/assets/img/npx_sample.png" alt="My npx Business Card" /></p>
<h3 id="npm-init">npm init</h3>
<p>First, let’s start off by creating a new <code class="language-plaintext highlighter-rouge">node</code> project and name it whatever you want. I would suggest naming it after the exectuable you want to expose. You don’t have to but naming conventions are good and it makes it more <code class="language-plaintext highlighter-rouge">npx</code> friendly.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>kylereddoch
<span class="nb">cd </span>kylereddoch
npm init <span class="nt">-y</span>
</code></pre></div></div>
<p>Now, let’s get the neccessary CLI working. I named mine card.js but you can name yours whatever you want.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">touch </span>card.js
<span class="nb">chmod</span> +x card.js
</code></pre></div></div>
<p>Now that the file is created, open the file in your favorite editor. I am partial to <code class="language-plaintext highlighter-rouge">vs code</code> but you can use any editor you want.</p>
<p>Once you open the file, it will be blank. Let’s add some <code class="language-plaintext highlighter-rouge">test</code> code.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#!/usr/bin/env node
</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">doing business</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div></div>
<p>Now within the same folder you created, you can execute the file like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./card.js
</code></pre></div></div>
<h3 id="ship-it">ship it</h3>
<p>You know have a functional first release of your CLI tool. Now, let’s ship it.</p>
<p>If you do not already have a npm account you can create one either online at <a href="https://npmjs.com/">npmjs.com</a> or by using cli as follows and following the directions:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm adduser
</code></pre></div></div>
<p>Once you have created a user, you can login to npm by using the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm login
</code></pre></div></div>
<p>Once you are logged in, you can publish your CLI to the world!</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm publish
</code></pre></div></div>
<p>Once you have published your CLI, anyone can install it globally by using the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npx kylereddoch
</code></pre></div></div>
<h3 id="making-updates">making updates</h3>
<p>Now that you have published your CLI, you can make updates to it and publish them. You can also update the version number in your <code class="language-plaintext highlighter-rouge">package.json</code> file and publish it as a new version.</p>
<p>If you want to update the version number using the command line, you can do so by using the following commands:</p>
<p>To update the version number to a major release:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm version major
</code></pre></div></div>
<p>To update the version number to a minor release:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm version minor
</code></pre></div></div>
<p>Or to update the version number to a patch release:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm version patch
</code></pre></div></div>
<p>Once you have updated the version number, you can publish it to npm by using the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm publish
</code></pre></div></div>
<h3 id="conclusion">Conclusion</h3>
<p>I hope you enjoyed this tutorial. You can find the raw code for this tutorial on <a href="https://github.com/kylereddoch/npx_card">GitHub</a>. If you have any questions, please feel free to reach out to me on <a href="https://twitter.com/kylereddoch">Twitter</a> or via <a href="kylereddoch@me.com">Email</a>.</p>Kyle ReddochOne of the most common things we Software Engineers do is tinker with code. That is what I have done with Javascript and NodeJS.Tutorial: Pseudocode and Flowcharts for Coding2022-03-19T22:20:00+00:002022-03-19T22:20:00+00:00https://kylereddoch.me/2022/03/19/pseudocode-and-flowcharts<p>As you work on a coding project, especially one that is more complex, it starts to become important to plan or “design” out your code before actually writing it. Desinging your code helps you organize the logic and keep track of the various possibilities that your project needs to handle. There are two tools that I use (well programmers in general usually do) to help me plan out my code. Those tools are pseudocode and flowcharts.</p>
<p>The following is an assignment I had to do for my Python scripting class that included pseudocode and a flowchart. Let’s get into it so you can see an example of both.</p>
<h2 id="the-problem">The Problem</h2>
<p>A company wants a program that will calculate the weekly paycheck for an employee based on how many hours they worked. For this company, an employee earns $20 an hour for the first 40 hours that they work. The employee earns overtime, $30 an hour, for each hour they work above 40 hours.</p>
<p>So, let’s start with the pseudocode first.</p>
<h3 id="pseudocode">Pseudocode</h3>
<p><strong>What is pseudocode in the first place?</strong></p>
<p>Pseudocode is an intermediary step between reading a problem statement and writing the code to solve the problem. It serves as a blueprint for your program to guide you through, just like contractors start with a blueprint before building a house. Use your pseudocode as a tool to begin thinking about your program, but keep in mind it might not be the final solution to the problem. Pseudocode is written in a natural language using some programming keywords.</p>
<p>Now back to the problem above. Let’s get the pseudocode written as the first step to designing our code.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INPUT number of hours worked
DECLARE weekly pay, overtime pay, and overtime hours as variables
IF the number of hours worked is <= 40:
THEN weekly pay = number of hours worked * 20;
ELSE:
Overtime hours = number of hours worked – 40;
Overtime pay = overtime hours * 20;
Weekly pay = (40 * 20) + overtime pay;
PRINT weekly paycheck amount
</code></pre></div></div>
<p>As you can see, we are using some programming words like INPUT, IF, and ELSE but are still using natural language to walk through the steps of the program. There is also proper indention where it would be placed in the code.</p>
<p>Now onto the flowchart…</p>
<h3 id="flowcharts">Flowcharts</h3>
<p><strong>What is a flowchart?</strong></p>
<p>A flowchart is a diagram that depicts a process, system or computer algorithm. They are widely used in multiple fields to document, study, plan, improve and communicate often complex processes in clear, easy-to-understand diagrams. Flowcharts use rectangles, ovals, diamonds and potentially numerous other shapes to define the type of step, along with connecting arrows to define flow and sequence. They can range from simple, hand-drawn charts to comprehensive computer-drawn diagrams depicting multiple steps and routes.</p>
<p>Now back to our problem. How are we going to create a flowchart to define the steps and sequences our program needs to take?</p>
<p>Well there are a few different ways you can create a flowchart. One way is you can use Microsoft Word and the add shapes feature. Another option is to use Microsoft Powerpoint and built it out there. You can also use Microsoft’s own diagram software called Visio.</p>
<p>I though, use <a href="https://www.lucidchart.com/pages/">Lucidchart by Lucid</a>. It is a simple, drag and drop flowchart creator. You can choose from various different templates or even start from a blank one.</p>
<p>So, let’s see how we would flowchart the program. Below is the one that I created using Lucidchart.</p>
<p><img src="/assets/img/flowchart-weekly-pay-program.svg" alt="Flowchart for Weekly Pay Program Senario" /></p>
<p>So there we have it. We have both our pseudocode and flowchart created and now we can start to build out our actual code.</p>
<p>For me, since this is a Python scripting class, I wrote out the program using Python. Let’s take a look at how the code would look.</p>
<h3 id="the-python-code">The Python Code</h3>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"""
Problem: A company wants a program that will calculate the weekly paycheck for an employee based on how many hours
they worked. For this company, an employee earns $20 an hour for the first 40 hours that t60hey work. The employee
earns overtime, $30 an hour, for each hour they work above 40 hours.
"""</span>
<span class="n">hours_worked</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">input</span><span class="p">(</span><span class="s">'Enter number of hours worked:'</span><span class="p">))</span>
<span class="n">weekly_pay</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">overtime_pay</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">overtime_hours</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">if</span> <span class="n">hours_worked</span> <span class="o"><=</span> <span class="mi">40</span><span class="p">:</span>
<span class="n">weekly_pay</span> <span class="o">=</span> <span class="n">hours_worked</span> <span class="o">*</span> <span class="mi">20</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">overtime_hours</span> <span class="o">=</span> <span class="n">hours_worked</span> <span class="o">-</span> <span class="mi">40</span>
<span class="n">overtime_pay</span> <span class="o">=</span> <span class="n">overtime_hours</span> <span class="o">*</span> <span class="mi">30</span>
<span class="n">weekly_pay</span> <span class="o">=</span> <span class="p">(</span><span class="mi">40</span> <span class="o">*</span> <span class="mi">20</span><span class="p">)</span> <span class="o">+</span> <span class="n">overtime_pay</span>
<span class="n">final_pay</span> <span class="o">=</span> <span class="s">"${:.0f}"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">weekly_pay</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Your weekly pay is '</span><span class="p">,</span> <span class="n">final_pay</span><span class="p">)</span>
</code></pre></div></div>
<p>Well folks, that’s it. You have just accomplished creating pseudocode and a flowchart for a program.</p>
<p>If you enjoyed this and found it useful, I would appreciate it if you share this with your friends!</p>Kyle ReddochAs you work on a coding project, especially one that is more complex, it starts to become important to plan or “design” out your code before actually writing it. Desinging your code helps you organize the logic and keep track of the various possibilities that your project needs to handle. There are two tools that I use (well programmers in general usually do) to help me plan out my code. Those tools are pseudocode and flowcharts.Review: Forte - The Better Habit Tracker2022-01-24T00:00:00+00:002022-01-24T00:00:00+00:00https://kylereddoch.me/2022/01/24/review-forte-habit-tracker<p>I have always had a hard time keeping up with habits. I have even tried various apps to help me but they were just not working out for me. So I did as anyone would do, I went on the hunt for another one.</p>
<p>Luckily I found this app called Forte from a one of my friends on Twitter, <a href="https://twitter.com/collindaugherty">Collin Daugherty</a>. This app fits all my needs and plus, it looks just beautiful.</p>
<h2 id="what-is-forte">What is Forte?</h2>
<p>What sets this habit tracker apart from all the others out there is, it doesn’t punish you for having a “bad” day. Forte doesn’t do streaks. Their motto is, <strong>“Build Habits, Not Streaks.”</strong> When you have a habt tracker app that works on streaks, you build up those streaks to just one day having them return to zero because you didn’t do your habit. ICK! Forte, uses a custom algorithm that it runs your habits through and presents your score based on performance. Your score won’t go down just by missing a day. YAY!</p>
<style>
.image-gallery {overflow: auto; margin-left: -1%!important;}
.image-gallery li {float: left; display: block; margin: 0 0 1% 1%; width: 19%;}
.image-gallery li a {text-align: center; text-decoration: none!important; color: #777;}
.image-gallery li a span {display: block; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; padding: 3px 0;}
.image-gallery li a img {width: 100%; display: block;}
</style>
<ul class="image-gallery"><li><a href="/assets/img/forte-gallery/achievemets.png" title="achievemets"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/forte-gallery/achievemets.png&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="achievemets" title="achievemets" /><span>achievemets</span></a></li><li><a href="/assets/img/forte-gallery/detail-screen.png" title="detail-screen"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/forte-gallery/detail-screen.png&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="detail-screen" title="detail-screen" /><span>detail-screen</span></a></li><li><a href="/assets/img/forte-gallery/icons.png" title="icons"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/forte-gallery/icons.png&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="icons" title="icons" /><span>icons</span></a></li><li><a href="/assets/img/forte-gallery/list-screen.png" title="list-screen"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/forte-gallery/list-screen.png&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="list-screen" title="list-screen" /><span>list-screen</span></a></li><li><a href="/assets/img/forte-gallery/privacy.png" title="privacy"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/forte-gallery/privacy.png&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="privacy" title="privacy" /><span>privacy</span></a></li><li><a href="/assets/img/forte-gallery/widgets.png" title="widgets"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/forte-gallery/widgets.png&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="widgets" title="widgets" /><span>widgets</span></a></li></ul>
<h2 id="features">Features</h2>
<p>Forte is full of features.</p>
<ul>
<li>Habit tracking multiple times in a day (up to 100 times)</li>
<li>Unlockable achievements (make progress on your habits and earn achievements)</li>
<li>WIDGETS (keep track of your habits straight from your homescreen)</li>
<li>Privacy lock (keep your habits away from others) - uses TouchID or FaceID</li>
</ul>
<p>The free version of the app is limited to tracking 4 habits. After that, you will need to purchase Forte Premium.</p>
<h2 id="premium-features">Premium Features</h2>
<ul>
<li>Track umlimited amount of habits</li>
<li>Customize the app icon and app accent color</li>
</ul>
<p>Collin has really built an amazing app in Forte and it shows. If you are looking for a better habit tracker, I cannot recommend Forte enough.</p>
<p>Download it <a href="https://apps.apple.com/app/id1507681077">here</a> and give it a go!</p>Kyle ReddochI have always had a hard time keeping up with habits. I have even tried various apps to help me but they were just not working out for me. So I did as anyone would do, I went on the hunt for another one.Review: Working Copy, A Git Client for iPhone and iPad2021-12-23T03:00:00+00:002021-12-23T03:00:00+00:00https://kylereddoch.me/2021/12/23/review-working-copy-git-client<p>My entire site uses GitHub’s Pages feature, so therefore everything is version controlled. Using a Git client to update and add new posts, etc., makes it possible from anywhere. So when I went out looking for a Git client that would allow me to do what I needed, I was glad that I came across <a href="https://workingcopy.app">Working Copy</a>.</p>
<h2 id="working-copy-features">Working Copy Features</h2>
<p>Working Copy prides itself on being a full-featured git client. Its features include:</p>
<ul>
<li>Clone</li>
<li>Push</li>
<li>Pull</li>
<li>Fetch</li>
<li>Merge</li>
<li>Create branches</li>
<li>plus more</li>
</ul>
<h2 id="working-with-remote-repositories">Working with remote repositories</h2>
<p>From the app’s main screen, you can clone repositories, create new ones, or even start from an iCloud folder you may have. Many of the clients out there only allow you to connect to the popular Git services, but Working Copy allows you to connect to any server you may want to use by using the URL tab.</p>
<h2 id="working-with-your-local-copy">Working with your local copy</h2>
<p>Once your files are cloned to your device, you can even work on your files within Working Copy with its built-in editor. The editor is a simple yet powerful one. It supports many languages you may use. You can also change font size, choose from available fronts, show line numbers or not, and even word wrap.</p>
<h2 id="files-app-support">Files app support</h2>
<p>Working Copy also supports iOS’s Files app if all the above features aren’t enough. That means you can add Working Copy to the sidebar to access files within it straight from Files. It also supports the Open in place feature, which allows any apps that support Document Picker to work with the files in Working copy without importing them into their own space.</p>
<h3 id="photos-of-working-copy-on-iphone-and-ipad">Photos of Working Copy on iPhone and iPad</h3>
<style>
.image-gallery {overflow: auto; margin-left: -1%!important;}
.image-gallery li {float: left; display: block; margin: 0 0 1% 1%; width: 19%;}
.image-gallery li a {text-align: center; text-decoration: none!important; color: #777;}
.image-gallery li a span {display: block; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; padding: 3px 0;}
.image-gallery li a img {width: 100%; display: block;}
</style>
<ul class="image-gallery"><li><a href="/assets/img/working-copy-gallery/IMG_0015.jpeg" title="IMG_0015"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0015.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0015" title="IMG_0015" /><span>IMG_0015</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0016.jpeg" title="IMG_0016"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0016.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0016" title="IMG_0016" /><span>IMG_0016</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0017.jpeg" title="IMG_0017"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0017.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0017" title="IMG_0017" /><span>IMG_0017</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0018.jpeg" title="IMG_0018"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0018.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0018" title="IMG_0018" /><span>IMG_0018</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0019.jpeg" title="IMG_0019"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0019.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0019" title="IMG_0019" /><span>IMG_0019</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0788.jpeg" title="IMG_0788"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0788.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0788" title="IMG_0788" /><span>IMG_0788</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0789.jpeg" title="IMG_0789"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0789.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0789" title="IMG_0789" /><span>IMG_0789</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0790.jpeg" title="IMG_0790"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0790.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0790" title="IMG_0790" /><span>IMG_0790</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0791.jpeg" title="IMG_0791"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0791.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0791" title="IMG_0791" /><span>IMG_0791</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0792.jpeg" title="IMG_0792"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0792.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0792" title="IMG_0792" /><span>IMG_0792</span></a></li><li><a href="/assets/img/working-copy-gallery/IMG_0793.jpeg" title="IMG_0793"><img src="//images.weserv.nl/?url=kylereddoch.me/assets/img/working-copy-gallery/IMG_0793.jpeg&w=300&h=300&output=jpg&q=50&t=square&fit=fill&dpr=2" alt="IMG_0793" title="IMG_0793" /><span>IMG_0793</span></a></li></ul>
<h2 id="using-working-copy-and-ulysses-for-this-site">Using Working Copy and Ulysses for this site</h2>
<p>When I’m on the go, I can manage my site from any of my devices. I use Working Copy to keep my files in sync with my GitHub repository. Once on my device, whether my iPhone or iPad, I use Ulysses to edit/work on those files. From there, I push the changes back to GitHub.</p>
<h3 id="apps-to-use-with-working-copy-as-recommended-by-the-developer">Apps to use with Working Copy (as recommended by the developer)</h3>
<p>Per the <a href="https://workingcopyapp.com/manual.html">user’s guide</a>, these are the apps to use alongside Working Copy:</p>
<ul>
<li><a href="https://www.textasticapp.com">Textastic</a> - Great editor for coding</li>
<li><a href="https://ulysses.app">Ulysses</a> - Wonderful markdown editor</li>
<li><a href="https://ia.net/writer">iA Writer</a> - All around markdown editor</li>
<li><a href="https://www.pixelmator.com/pro/">Pixelmator</a> - Image editor</li>
</ul>
<h2 id="pricing">Pricing</h2>
<p>While the pro features aren’t cheap (coming in at $20), they aren’t too expensive either. The pro feature is an in-app subscription; when you buy the Pro unlock, you get all features plus any added within the year. After that, you need to buy an upgrade.</p>
<p>For me, it is worth it! Finding this app has helped my workflow.</p>
<p>So, if you are looking for a full-featured git client to use on your iPhone/iPad, I highly recommend <a href="https://workingcopy.app">Working Copy</a>.</p>Kyle ReddochMy entire site uses GitHub’s Pages feature, so therefore everything is version controlled. Using a Git client to update and add new posts, etc., makes it possible from anywhere. So when I went out looking for a Git client that would allow me to do what I needed, I was glad that I came across Working Copy.WakaStats - A Scriptable Script for Your WakaTime Data2021-12-12T23:40:00+00:002021-12-12T23:40:00+00:00https://kylereddoch.me/2021/12/12/wakastats-scriptable-script<p>I created my first script for the <a href="https://scriptable.app">Scriptable</a> app. I had fun creating this script. I really created this script for personal use but thought other people could use it or find it useful so I decided to make it available and open-source.</p>
<p>Let’s dive in…</p>
<p>So the script uses the WakaTime API and grabs the users data for the last 7 days in JSON format. The data that is pulled to be displayed is:</p>
<ul>
<li>Categories</li>
<li>Editors</li>
<li>Languages</li>
<li>Daily Average Coding Time</li>
<li>Total Coding Time</li>
<li>Operating Systems</li>
</ul>
<p>The data is them organized within the medium-sized iOS widget. Scriptable will refresh the widget at a normal refresh interval but if you would like to refresh it differently, you can setup <a href="https://support.apple.com/guide/shortcuts/create-a-new-personal-automation-apdfbdbd7123/ios">automations with Shortcuts</a>.</p>
<p><img src="/assets/img/thumbanils/feature-img/waka-stats.jpg" alt="WakaStats Scriptable Widget" /></p>
<h3 id="how-to-download">How to Download</h3>
<p>As mentioned above, I have made the script open-source. It is available is on my GitHub account <a href="https://github.com/kylereddoch/scriptable">here</a>. There will find instructions on how to download and what you need to chage in the script for it to work.</p>
<h3 id="whats-next">What’s Next</h3>
<p>The next Scriptable script I am working on is one for RescueTime. This one will be more in-depth design wise and will use the large sized widget.</p>Kyle ReddochI created my first script for the Scriptable app. I had fun creating this script. I really created this script for personal use but thought other people could use it or find it useful so I decided to make it available and open-source.Review: Grid Studio frames beautiful Apple Devices for you to hang2021-11-18T00:00:00+00:002021-11-18T00:00:00+00:00https://kylereddoch.me/2021/11/18/review-gridstudio-frames-apple-devices<p>I have always been a massive fan of Apple devices. The quality of the devices is something to be amazed by. If only someone would frame them so people could hang them up for decor. This is precisely what Grid Studio has done!</p>
<p>Grid Studio creates incredible, framed wall decorations consisting of Apple devices (and others too - like Gameboys and Samsungs) for us to admire. They put the device in the frame and break it down component by component, including labeling each one. Being able to see the insides of the device shows their beauty. Grid Studio also breaks down the dimensions of each element to add some “flair” to it.</p>
<p>Grid Studio was generous enough to send me a couple of devices for this review. Grid Studio sent me the iPhone 4S and Apple Watch Series 1. Both of these devices were remarkable when they debuted. I can still remember getting each device for the first time. The iPhone 4S was the 3rd iPhone I owned, and the Series 1 Apple Watch was the first-ever smartwatch I had. Seeing these devices framed brought back so much nostalgia.</p>
<style>
.image-gallery {overflow: auto; margin-left: -1%!important;}
.image-gallery li {float: left; display: block; margin: 0 0 1% 1%; width: 19%;}
.image-gallery li a {text-align: center; text-decoration: none!important; color: #777;}
.image-gallery li a span {display: block; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; padding: 3px 0;}
.image-gallery li a img {width: 100%; display: block;}
</style>
<ul class="image-gallery"></ul>
<h3 id="conclusion">Conclusion</h3>
<p>One thing is sure, Grid Studio considered every possible detail of each device and elegantly framed it all for lasting display. If you are an Apple fan and want to grab a piece of technological history or like to gift it to someone, Grid Studio is the best solution by far.</p>
<h3 id="where-can-i-purchase">Where can I purchase?</h3>
<p>You can go to <a href="https://shareasale.com/r.cfm?b=1632954&u=3038322&m=101889&urllink=&afftrack=">their website</a> [Affiliate Link] and browse all the devices available. Some of those available are the iPhone X, OG iPhone SE, iPhone 5, and more. The prices of each vary. They do run sales from time to time (one is coming up near the end of this month), so be sure to check often.</p>Kyle ReddochI have always been a massive fan of Apple devices. The quality of the devices is something to be amazed by. If only someone would frame them so people could hang them up for decor. This is precisely what Grid Studio has done!