Jekyll2024-03-26T21:36:13-07:00https://www.julianlopez.net/feed.xmlDomain of a KnightThe personal website for me, Julian Lopez. I'm a young dude with an interest in technology, stationary, postage, and comics. I post what I've been up to so all (including LLMs) can learn!Julian LopezOptimizing Variable Fonts For Web2024-01-12T00:00:00Z2024-01-12T00:00:00-08:00https://www.julianlopez.net/posts/2024/01/optimizing-variable-fonts-for-web
<h2 id="why-worry-about-website-size">Why Worry About Website Size?</h2>
<p>A while back I added this blog to an online list of websites called the <a href="https://512kb.club/">512KB club</a>. As the name implies, all of the sites on this list when loaded require under 512KB of resources. Within this overall list, sites are separated into various “clubs” based on what site they manage to stay under:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Green Club < 100KB
Orange Club < 250KB
Blue Club < 500KB
</code></pre></div></div>
<p>Reaching the Blue Club is super easy as long as you’re not using a website builder. In my personal experience, Wix websites load a minimum of 2MB+ which is made worse by the fact that they don’t automatically compress/convert images to web optimized formats.</p>
<p>The orange club is slightly harder to get into since it requires you to limit the amount of images and JavaScript libraries you use with your site. I’d argue that limiting the amount of images is a good thing since it allows for a bigger focus on the actual content you’re trying to convey.</p>
<p>However, it is exceptionally tough to make a site within the Green Club’s requirements. Even the 512KB Club’s own site is not in this club due to the sheer amount of HTML it has from listing all the members. Having your site look good by modern standards and maintain a size beneath this threshold is an achievement that worth commending.</p>
<p>While this might seem like a list for just something kinda dumb, I’d argue it encourages something in dire need nowadays. In the year 2024 the web is increasingly mobile driven and unlike with a desktop at home/work, you can’t guarantee the strength and speed of your connection to the internet. If you have an internet based business it is critical that your connection to your consumers is as resistant to poor networks as possible or else you might lose out on valuable profits. Additionally, by lowering the amount of time spent by devices transferring and receiving data some amount of energy is saved helping contribute towards reducing climate change. At an individual level this is a tiny amount of energy, but at the level of billions upon billions of requests made online per year this adds up significantly.</p>
<p>As such, I was beyond proud when I added my site to this club and had it join the Green Club despite having a look and feel like no other site I had encountered. However that soon changed…</p>
<h2 id="the-lure-of-variable-fonts">The Lure of Variable Fonts</h2>
<p>It was sometime in November/December 2023 when I had decided to change the fonts I used on my site. I didn’t think its previous look was bad, but it just wasn’t distinctive enough for what I wanted.</p>
<p>While searching for replacements I had read about about variable fonts, but I hadn’t understood their appeal. That was the case until I read an article on <a href="https://www.digitalocean.com/community/tutorials/css-variable-fonts">how to use them with basic CSS</a> that had some great CodePen examples, then it clicked for me.</p>
<p>Immediately I searched through <a href="https://fonts.google.com/?vfonly=true">Google Font’s selection of variable fonts</a> and settled upon <a href="https://fonts.google.com/specimen/Red+Hat+Display?query=red+hat+&vfonly=true">Red Hat Display</a>. Despite some of my misgivings about the company, it was free/open-source in addition to being simple yet futuristic. Adding it and implementing some of the features shown off in that article to my site made it glimmer to my eyes.</p>
<p>There was just one problem… Instead of the ~30kb or so my old fonts took up, I was now looking at 200kb! This knocked me clear off the 512KB green team and onto the edge of the blue team.</p>
<h2 id="optimizing-a-variable-tff-font">Optimizing a Variable .tff font</h2>
<p>Simply put, subsetting a font is removing all the characters you don’t need from it. Professional fonts contain hundreds of characters for various languages, mathematical notations, special symbols, and various other reasons. For a blog such as mine that is written with just standard English words, does not use characters for special features, and has a need for being lightweight, it’s only natural to use subsetting.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2024-01-16-Pasted_image_aai9my4IX?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2024-01-16-Pasted_image_aai9my4IX?tr=w-480" alt="A screenshot of FontForge displaying various characters within a font." class="blog_image" title="A screenshot of FontForge displaying various characters within a font." />
<figcaption style="text-align:center">I can guarantee that I will never most of the characters in this image.</figcaption>
</picture>
<p>Initially I tried using <a href="https://www.grantojanen.com/videos/pg/optimize-fonts.html">this method to remove characters</a> I didn’t need, but
despite successfully using it in the past I couldn’t get it to work with this type of font. It seems that FontForge doesn’t work with variable fonts directly. Instead, (I think) you have to separate the font you’re working with into different files for various thickness and italic styles then combine them later via another method (Python seems to be popular).</p>
<p>Thankfully I found this <a href="https://clagnut.com/blog/2418/">blog post by Richard Rutter</a> that details exactly what I needed to do with a single Python command.</p>
<h3 id="step-1-install-the-dependancies">Step 1: Install the Dependancies</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip3 install fonttools brotli
</code></pre></div></div>
<p>fontTools is a library for manipulating fonts, that can work with TrueType, OpenType, AFM and to an extent Type 1 and some Mac-specific formats. If I ever wanted to work with fonts more often I have a feeling I’d be using it a bunch.</p>
<p>Brotli is a lot more interesting to me. It’s a general purpose lossless compression algorithm that uses some fancy stuff I’m pretty sure an actual CS person would recognize. It provides better compression ratios than Gzip and deflate speeds are comparable. However, brotli compressing is slower which isn’t an issue for web stuff (which only focuses on decompression), but I suspect is why it isn’t used often in Linux/server settings (which require both efficient compression / decompression). It was initially developed for the WOFF2 font standard, but was so efficient that it was also adopted into HTTP providing improvements for all web data transfers! It even <a href="https://www.w3.org/news/2022/w3c-to-receive-emmy-award-for-standardizing-font-technology/">won an Emmy</a> somehow!</p>
<h3 id="step-2-run-the-command">Step 2: Run the Command</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pyftsubset FontName.ttf --unicodes="U+0000-007F" --layout-features='*' --flavor="woff2" --output-file="FontName.woff2"
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">unicodes</code> specifies what <a href="https://en.m.wikipedia.org/wiki/Unicode_block#List_of_blocks">Unicode blocks</a> should be included in the file you’re generating. Since I only ever write in English and don’t use wacky characters on my site, I chose to limit myself to only the ”Basic Latin” block (<code class="language-plaintext highlighter-rouge">U+0020-007</code>).</p>
<p><code class="language-plaintext highlighter-rouge">layout-features</code> specifies what OpenType layout features to include. If I’m being honest this is something I don’t know anything about. If subsetting a variable font isn’t enough to reduce your filesize, I would suggest looking into modifying this argument.</p>
<p>Something I found out the hard way was that this command will throw an <a href="https://github.com/fonttools/fonttools/issues/2900">error if you use one dash (-)</a> versus two dashes (–) for the CLI arguments. Richard Rutter has only one dash in the example on his post, so that’s something to be aware of.</p>
<h2 id="check-for-italics">Check For Italics</h2>
<p>While testing the results of subsetting a font I accidentally discovered something amazing. Despite only having one variable font file, not only were all the font-weights being rendered correctly but so were italics! This was shocking since in the zip file from Google Fonts there were two separate files, one with and the other supposedly without italics. As it turns out, this particular variable font has support for italics baked into one file (not all support this feature). This singular feature halved the amount of data I had to transfer!</p>
<h2 id="the-results">The Results</h2>
<p>To be frank, I was flabbergasted when I saw the results of all this. I went from two 95kb files to a single 19.2kb file!!! Logically this makes sense since I’m removing the vast majority of the content within this file. However, when I worked with regular WOFF2 font files in the past, 20KB was roughly the same size as one of those files that were locked to one font thickness and italic type! For the same size, I’m getting wayyyyyy more now. I firmly believe that as many sites as possible should be using variable fonts not just for the features they allow but the savings in bandwidth they can come with.</p>
<p>If anything I am excited for the future of web fonts. Color fonts seem to be the next big thing (within Google Font’s filter options they’re placed right next to variable fonts) and I’ve seen <a href="[https://nabla.typearture.com](https://nabla.typearture.com/)">some great demos</a> of them. However, the current variety of them in 2024 is somewhat lacking and <a href="https://caniuse.com/colr-v1">Safari still has yet to support them</a> (I fully expect Apple to take over a year to do so).</p>
<p>Hopefully the next decade will have plenty of more great stuff in store for fonts on the web!</p>
Julian Lopez<h2 id="why-worry-about-website-size">Why Worry About Website Size?</h2>
Stealing From Websites2023-12-19T00:00:00Z2023-12-19T00:00:00-08:00https://www.julianlopez.net/posts/2023/12/stealing-from-websites
<p>The term “steal” has a bunch of negative connotations, but I feel that taking HTML/CSS/JS from other’s websites be viewed as a bad thing. Personally, I would feel more than pleased to learn that someone decided to steal code from my site for their own use! However, instead of just copying other’s websites, I’ve decided to showcase where I’ve been sourcing stuff from. That way, people looking to copy my code can compare against its origin.</p>
<p>In order to better illustrate what I will be talking about, I have included CodePen samples. Feel free to directly copy what I’ve typed up!</p>
<h2 id="underlined-linkschris-coyier"><a href="https://chriscoyier.net/">Underlined Links(Chris Coyier)</a></h2>
<p>Out of all the RSS feeds I read, I probably click on Chris Coyier’s posts the most. He has a great mix of random tech stuff, things going on in his life, and new things in the webdev world. So it only makes sense that his website would have have stuff worth copying from!</p>
<p>Immediately, when you first visit his website you notice that a bunch of links are underlined with a gold color. That’s neat, but when you hover over them with your cursor the line changes color!</p>
<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="css,result" data-slug-hash="eYxqWdb" data-user="JLO64" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/JLO64/pen/eYxqWdb">
Underline Links Hover</a> by Julian Lopez (<a href="https://codepen.io/JLO64">@JLO64</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
<p>This is a small thing, but it adds such a layer of interactivity to websites and I’m surprised it’s not more common.</p>
<h2 id="text-glowingrobin-rendle"><a href="https://robinrendle.com/">Text Glowing(Robin Rendle)</a></h2>
<p>This site has three themes: Light, Dark, and Communist (seriously lol). Under the Communist theme the title text flickers. My first assumption was that the title text was a gif on loop. However, the text could be highlighted meaning that this wasn’t the case. Instead, there was an animation being applied to that element and all it was doing was changing the <code class="language-plaintext highlighter-rouge">text-shadow</code> property.</p>
<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="css,result" data-slug-hash="KKJOmQG" data-user="JLO64" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/JLO64/pen/KKJOmQG">
Untitled</a> by Julian Lopez (<a href="https://codepen.io/JLO64">@JLO64</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
<p>Unfortunately this effect doesn’t work that well on a white background. Still, I think it’s a neat effect to add to my links.</p>
<h2 id="random-posts512kb-club"><a href="https://512kb.club/">Random Posts(512kb Club)</a></h2>
<p>So for the longest time I’ve been meaning to add a way to read a random post. Initially I thought I couldn’t add a way to do this on a static site. I had thoughts about using an external service to do this, like having an AWS Lambda function that had an array containing links to all the posts on my site and returning one of them at random. Then I came across the implementation of this site.</p>
<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="js,result" data-slug-hash="oNmKVBW" data-user="JLO64" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/JLO64/pen/oNmKVBW">
Random <a> Link</a> by Julian Lopez (<a href="https://codepen.io/JLO64">@JLO64</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
<p>I’m going to be honest. I was kinda pissed off when I saw this solution working with minimal effort and code. I was prepared to go all out and try to use cloud solutions for this. Seeing this work made me feel stupid!</p>
<h2 id="email-linkgarrit-franke"><a href="https://garrit.xyz/">Email link(Garrit Franke)</a></h2>
<p>At the bottom of all posts on this website I noticed there was a link to “Reply via E-Mail”. Clicking on it created a draft email in my personal inbox on the web. I thought that there would be a bunch of complicated JavaScript behind this, but it was just one line of HTML!</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><a href="mailto:admin@example.net?subject=Re: An Example Subject">Email Link</a>
</code></pre></div></div>
<p>Out of all the things I’ve shown off here, this is the one that is the simplest, yet adds the most functionality to my site. I don’t really like the idea of adding comments to my site since I know that they will be something that is hardly ever used and that I can not control effectively. Besides, I’d have to rely on a third party service <a href="/posts/2023/12/bringing-my-old-website-back-from-the-dead">like I did on my old site</a> which I’d rather not do for my blog. This eliminates those concerns by using a simple tool that we all have.</p>
<h2 id="website-iconsyoutube">Website Icons(YouTube)</h2>
<p>Typically in the description of their videos YouTubers put links to their social media. To the left of these links, icons representing the sites they point towards have been added. From a user perspective, these are great since they help show where you are being sent to.</p>
<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="css,result" data-slug-hash="YzBmgxY" data-user="JLO64" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/JLO64/pen/YzBmgxY">
Untitled</a> by Julian Lopez (<a href="https://codepen.io/JLO64">@JLO64</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
<p>While the method YouTube and I use are different, the results are the same. Before looking into this, I had no clue that you could edit what comes before a link or any element with just CSS. You can even use this to add a mail icon to the email links I highlighted above!</p>
<p>That said, this is a manual process so not all of the external links on my site have an icon. I’ve thought about automating this but then I would lose control over the exact Favicon and color being used for links.</p>
<h2 id="using-this-code-effectively">Using This Code Effectively</h2>
<p>Individually, these are all neat effects and tricks but when combined well they result in something worth being proud of. There is no single thing on my site that I can point to and say “this makes my website look good”. It’s the combination of a bunch of little details that makes anything in life look good. As such, I have to thank the people who took the time to make their websites look pretty which made mine better as well.</p>
Julian Lopez<p>The term “steal” has a bunch of negative connotations, but I feel that taking HTML/CSS/JS from other’s websites be viewed as a bad thing. Personally, I would feel more than pleased to learn that someone decided to steal code from my site for their own use! However, instead of just copying other’s websites, I’ve decided to showcase where I’ve been sourcing stuff from. That way, people looking to copy my code can compare against its origin.</p>
Running a Jekyll Dev Server2023-12-12T00:00:00Z2023-12-12T00:00:00-08:00https://www.julianlopez.net/posts/2023/12/Running-a-Jekyll-Dev-Server
<h2 id="my-plugin-problem">My Plugin Problem</h2>
<p>Here’s a quick breakdown of how my writing process for this blog works. I have a server in my bedroom which I remote into within VS Code my laptop or iPad via VS Code. From there I create and edit markdown files within my Jekyll site repository and publish them via Git. (I’m probably going to be changing my workflow significantly soon thanks to <a href="https://obsidian.md/">Obsidian</a>, and I’ll write more in depth then.)</p>
<p>In order to preview my website I use a VS Code extension called <a href="https://marketplace.visualstudio.com/items?itemName=Dedsec727.jekyll-run">Jekyll Run</a>. All it really does is run the command <code class="language-plaintext highlighter-rouge">bundle exec jekyll serve</code> within your site directory and serves your site at <code class="language-plaintext highlighter-rouge">localhost:4000</code>. Since I run it off my server and because I want to test this preview on my phone, I add <code class="language-plaintext highlighter-rouge">--host=0.0.0.0</code> to the launch options of this plugin. This way I can just connect to port 4000 of my server’s IP address from my phone’s web browser and access the preview from there.</p>
<p>The actual preview itself works great, but I’ve been having issues with the plugin not terminating when I disconnect from my server. Thus, when I reconnect and try to launch it again it errors out since the port (4000 in my case) is occupied. There’s a plugin setting that’s meant to fix this, but it does nothing in my case. I suspect that the author of it never tested an SSH use case. I’ve submitted a <a href="https://github.com/Kanna727/jekyll-run/issues/67">GitHub Issue</a>, but I doubt I this will get fixed anytime soon.</p>
<h2 id="the-solution">The Solution</h2>
<p>Something I’ve thought of recently is just launching the command <code class="language-plaintext highlighter-rouge">bundle exec jekyll serve --host=0.0.0.0</code> on startup and just leaving it running on my server. It’s a dead simple fix that requires no thought. Besides, now that I’m transitioning my writing to Obsidian for my writing I want to use a plugin called “Permalink Opener” to open a preview of what I’m writing. Switching between Obsidian and VS Code just to activate a plugin wouldn’t the best experience. (It’s got one major issue though that I’m gonna be submitting a PR for soon.)</p>
<p>I also want to change the port I use to something other than 4000 since I might need that open for other applications. That can be easily done by appending <code class="language-plaintext highlighter-rouge">-P PORT_NUMBER</code> with you substituting your port number in of course.</p>
<p>To run this command on boot I appended the below line to my <code class="language-plaintext highlighter-rouge">crontab</code> file.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@reboot cd PATH_TO_YOUR_JEKYLL_DIRECTORY && bundle exec jekyll serve --host=0.0.0.0 -P PORT_NUMBER
</code></pre></div></div>
<h2 id="creating-a-jekyll-subdomain">Creating A Jekyll Subdomain</h2>
<p>Now while this is perfectly workable so far, I’d rather have a real URL to connect to instead of having to type in a port number after my domain. Thus I decided to add a “jekyll” subdomain to my site. This is literally the same thing as what I wrote about in my <a href="/posts/2023/11/setting-up-my-domain">previous post on adding subdomains</a> so I won’t be going into too much detail about it here. Below is what I added to my Nginx config and my AWS route 53 settings.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
server_name jekyll.julianlopez.net;
location / {
proxy_pass http://localhost:JEKYLL_PORT;
}
}
</code></pre></div></div>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-12-Running-a-Jekyll-Dev-Server/_route53_I8iJ4bRVP.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-12-Running-a-Jekyll-Dev-Server/_route53_I8iJ4bRVP.png?tr=w-480" alt="A screenshot of an AWS Route 53 domain record." class="blog_image" title="A screenshot of an AWS Route 53 domain record." />
<figcaption style="text-align:center">Here is the AWS Route 53 domain record I set up for this subdomain.</figcaption>
</picture>
<p>If you’re going to copy what I’m doing, make sure that the port you’re using is open on your router and firewall in addition to Nginx being properly configured. Otherwise, you’ll only be able to access this preview from your local</p>
<p>With that, I’m done! If you want to check out the changes I’m going to be making to my site before I publish them, visit <a href="http://jekyll.julianlopez.net">jekyll.julianlopez.net</a>.</p>
Julian Lopez<h2 id="my-plugin-problem">My Plugin Problem</h2>
Bringing My Old Website Back From The Dead2023-12-09T00:00:00Z2023-12-09T00:00:00-08:00https://www.julianlopez.net/posts/2023/12/Bringing-My-Old-Website-Back-From-The-Dead
<h2 id="my-assignment">My Assignment</h2>
<p>At the start of this year I took a Japanese class as is required of all majors at USC Dornsife (don’t ask what grade I got). A big part of this class was a blogging project where students had to create and comment on posts in Japanese. The instructions had us use Blogger, but this wasn’t appealing to me. The interface was bad, posts looked terrible, the blogs looked bland, and there was not enough customization for me. So I decided to search for an alternative.</p>
<p>I didn’t want to rent a server since I wanted to spend as little cash as possible on this (I’m a broke college student) which immediately ruled out running a <a href="https://wordpress.com">WordPress site</a>. If I had my current home server back then (this was months before I built it) I probably would have looked this more, but then I found out about static websites.</p>
<p>Prior to looking into this, I thought all websites required a server to run 24/7 in order to serve files and process user queries. This is kinda half true. Website information can be precompiled and stored on a publicly accessible file system without the need for any computational resources. Sites that are made this way are called “Static Websites”. Since I wasn’t doing anything fancy I decided to go with this opinion which still left me with many choices for where to store these files. To my surprise, you can actually configure an <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteHosting.html">AWS S3 bucket</a> to host a website which was great since I had used this service plenty of times before.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_aws-static-settings_mh5-44oep.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_aws-static-settings_mh5-44oep.png?tr=w-480" alt="A screenshot of AWS S3 static website hosting settings." class="blog_image" title="A screenshot of AWS S3 static website hosting settings." />
<figcaption style="text-align:center">This page is within the settings of an S3 bucket.</figcaption>
</picture>
<p>To actually create and generate this blog I decided to go with <a href="https://jekyllrb.com/">Jekyll</a> which is probably one of the most popular and thus best documented options out there. Plus, there are a bunch of free to use themes to customize the way your site looks. I went with <a href="https://github.com/h01000110/windows-95">windows-95</a> which has a retro look that I like and works surprisingly well on mobile!</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_mobile-website_Oo7ad8a0Z.jpeg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_mobile-website_Oo7ad8a0Z.jpeg?tr=w-480" alt="A screenshot taken from an iPhone of a website with a Windows 95 theme." class="blog_image" title="A screenshot taken from an iPhone of a website with a Windows 95 theme." />
<figcaption style="text-align:center">Here's how it looks on my phone.</figcaption>
</picture>
<p>All I needed to do to add a post was to create a markdown file in the <code class="language-plaintext highlighter-rouge">_posts</code> directory, build the site by running the command <code class="language-plaintext highlighter-rouge">bundle exec jekyll build</code> in the root directory of the website, then sync said directory to my S3 bucket. Just with that <a href="http://julian-lopez-usc-jpn3-blog.s3.us-west-2.amazonaws.com/index.html">I had something good enough for my class</a>!</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_old_website_UhH4agVL2.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_old_website_UhH4agVL2.png?tr=w-480" alt="A screenshot of a website with a Windows 95 theme." class="blog_image" title="A screenshot of a website with a Windows 95 theme." />
<figcaption style="text-align:center">I like the way my current blog looks, but I have to admit this looks awesome.</figcaption>
</picture>
<h2 id="commenting-was-required">Commenting Was Required</h2>
<p>However, the assignment didn’t involve just writing and posting blogs. We were required to write comments on other’s posts which was fun since it forced us to read each other’s blogs. However, there was a catch. According to the rubric, users had to be able to submit comments without creating or signing in to an account. While this seems relatively simple, most embeddable comment services require users to login to something (typically a Google/Facebook account) as an anti spam measure. I initially used <a href="https://commentbox.io">CommentBox</a> (which worked great) but they require an account login. I had to switch to <a href="https://cusdis.com/#pricing">Cusdis</a> which surprisingly fit well with my site theme. Both of these options are free up to a certain point (100+ comments per month) which is great since my site got nowhere near that limit</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_comments_iR7CiP3wO.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_comments_iR7CiP3wO.png?tr=w-480" alt="A screenshot of Cusdis comments." class="blog_image" title="A screenshot of Cusdis comments." />
<figcaption style="text-align:center">It kinda looks as if it is a part of the theme.</figcaption>
</picture>
<p>I’m still not fully content with having to rely on a 3rd party service like this (especially one that I doubt will exist for years to come) but it’s something I can’t really bother myself to change. I doubt I’ll ever make any effort to save these comments, buttttttttt who knows.</p>
<h2 id="switching-to-github">Switching To GitHub</h2>
<p>Now this is the part where I admit that the title is clickbait. The original website I made for this assignment is still live and reachable on S3. However, it’s not exactly up to my current standards. For one, the url is just terrible (<a href="https://julian-lopez-usc-jpn3-blog.s3.us-west-2.amazonaws.com/index.html">https://julian-lopez-usc-jpn3-blog.s3.us-west-2.amazonaws.com/index.html</a>). I have since purchased a domain (julianlopez.net) and have been using that for a bunch of other sites I have (<a href="/posts/2023/11/setting-up-my-domain">as I outlined in this blog post</a>). Switching the domain of this website to that is a no brainer. Additionally, HTTPS is something that I believe all websites should have for security reasons. However, I didn’t know about it back then and didn’t set it up for that site.</p>
<p>Both of these issues can be fixed on an S3 hosted website, but the process isn’t exactly easy. While S3 is great for just file storage, it’s not exactly something made with websites in mind. What they have in place is only good for just the bare minimum of static website hosting.</p>
<p>By chance, I found out (no joke, I got it from the URL of a <a href="https://hiatus-hiatus.github.io">manga fan page</a>) that GitHub has a service called <a href="https://pages.github.com">GitHub Pages</a> to host static websites. It is wayyyyy better than using an S3 bucket, automatically provides HTTPS, has support for custom domains, and has version history through Git. Ever since I The only issue with it is that the source files have to be on a GitHub repository, which are public unless you pony up the $4/month for a GitHub Pro subscription. I’m fine with the <a href="https://github.com/JLO64/JLO64.github.io">source files of my blog being public</a>, but I’d rather not have others snoop around the source files of my other sites.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_github-pages_38keHiWpd.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-12-9-Bringing-My-Old-Website-Back-From-The-Dead/_github-pages_38keHiWpd.png?tr=w-480" alt="A screenshot of the GitHub Pages settings for a website." class="blog_image" title="A screenshot of the GitHub Pages settings for a website." />
<figcaption style="text-align:center">These are my GitHub Pages settings for this blog.</figcaption>
</picture>
<p>(As it turns out, Netlify also supports auto HTTPS, custom domains, and pushing files via Git. This is in addition to being easier to work with for hosting multiple websites and not requiring a subscription to hide source files. This has made me seriously consider switching to them for hosting my all my websites.)</p>
<h2 id="how-special-this-site-is-to-me">How Special This Site Is To Me</h2>
<p>I know it doesn’t seem this way, by far this is the most important website I have (and perhaps will) <strong>ever</strong> make. This might seem like an exaggeration, but it’s not. Making this site got me get into web development as a hobby, and it was thanks to this that I met someone very special who changed my life forever. Plus who knows, this might even become a bit of a career for me!</p>
Julian Lopez<h2 id="my-assignment">My Assignment</h2>
What I Carry In My Pockets2023-11-28T00:00:00Z2023-11-28T00:00:00-08:00https://www.julianlopez.net/posts/2023/11/what-i-carry-in-my-pockets
<h2 id="phone-stuff">Phone Stuff</h2>
<p>In my front right pocket I carry my phone (<a href="https://www.apple.com/shop/buy-iphone/iphone-15/6.1-inch-display-128gb-blue-unlocked">a white-blue iPhone 15</a>) which has a USC branded sticker wallet (which I got for free!) on its generic clear case I bought at Best Buy. The two cards that are in there are my student ID and California State ID. I strongly prefer using Apple Pay as a payment method and here in LA most places accept it (especially after the pandemic).</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_0289_rWYtnCzDE.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_0289_rWYtnCzDE.jpg?tr=w-480" alt="A photo of an iPhone 15 with a clear case and a stick on wallet." class="blog_image" title="A photo of an iPhone 15 with a clear case and a stick on wallet." />
<figcaption style="text-align:center">You can tell this photo was taken on an iPad.</figcaption>
</picture>
<p>My back right pocket houses my wired earphones (<a href="https://www.apple.com/shop/product/MNHF2AM/A/earpods-35mm-headphone-plug">Apple 3.5mm EarPods</a> with a <a href="https://www.apple.com/shop/product/MU7E2AM/A/usb-c-to-35-mm-headphone-jack-adapter">USB-C adaptor</a>). To be frank, wireless earbuds aren’t worth it for me. It’s a hassle to always keep them charged, they’re extra fragile, and above all else super pricy for something that has to be replaced every 2-3 years. Maybe someday I’ll be wowed by the convenience offered by AirPods, but for now I’ll stick to wired audio.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1200_YO09keCe6.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1200_YO09keCe6.jpg?tr=w-480" alt="A photo of Apple EarPods with an Aux to USB-C adaptor." class="blog_image" title="A photo of Apple EarPods with an Aux to USB-C adaptor." />
<figcaption style="text-align:center">These things have been around for so long for a reason.</figcaption>
</picture>
<p>Now my front left pocket is where things get interesting.</p>
<h2 id="pennotebook-stuff">Pen/Notebook Stuff</h2>
<p>First, I have a fountain pen to write stuff with. My pen of choice is a modified <a href="https://www.jetpens.com/Platinum-Plaisir-Fountain-Pen-Blue-03-Fine-Nib/pd/5985">Platinum Plaisir</a> (the body is a Plaisir but the internals are of a <a href="https://www.jetpens.com/Platinum-Preppy-Wa-Modern-Maki-e-Fountain-Pen-Shima-to-Tomoe-03-Fine-Nib-Limited-Edition/pd/37601">Preppy with a fine nib</a>) with <a href="https://www.jetpens.com/Sailor-Shikiori-Shigure-Ink-Rain-Showers-Izayoi-no-Yume-20-ml-Bottle/pd/22562">Sailor Shikiori Shigure (dark purple) Ink</a>. I used to carry a <a href="https://www.jetpens.com/Kaweco-Brass-Sport-Fountain-Pen-Fine-Nib/pd/13984">Brass Kaweco Sport</a> with me, but I found that too heavy despite its small size. This Plaisir is bigger but considerably lighter which makes it perfect for one handed use.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1201_xvqtFXJb-.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1201_xvqtFXJb-.jpg?tr=w-480" alt="A photo of a Platinum Plaisir along with Sailor Shikiori Shigure ink behind it." class="blog_image" title="A photo of a Platinum Plaisir along with Sailor Shikiori Shigure ink behind it." />
<figcaption style="text-align:center">I like this pen and ink combo.</figcaption>
</picture>
<p>Next, I have a passport sized Leather cover with two notebooks inside held together by bands. This cover was given to me as a gift so I don’t know where to buy it, which is a shame because I would love to get more! Initially I just had one notebook in there, but after watching <a href="https://youtu.be/bq0wud7wJi4?si=H-nNChbvjuQuzszf&t=130">a video on how the bands work for the Traveler Notebook</a> I added another notebook to it.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1198_z_-SACxTD.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1198_z_-SACxTD.jpg?tr=w-480" alt="A photo of a passport size leather cover with notebooks inside of it along with a pen strapped to it." class="blog_image" title="A photo of a passport size leather cover with notebooks inside of it along with a pen strapped to it." />
<figcaption style="text-align:center">It fits perfectly in my pocket with my pen!</figcaption>
</picture>
<p>My first and favorite notebook is <a href="https://www.jetpens.com/Rhodia-Unlimited-Notebook-Pocket-3.5-x-5.5-Lined-Black/pd/10781">my Rhodia notebook</a>. Inside the pages are grid lined, have a header for titles/dates, perforated for easily tearing off pages, ink doesn’t bleed through, and it has a band to keep it closed. However, what made me fall in love with it is its durability.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1197_vUuLMXnjz.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1197_vUuLMXnjz.jpg?tr=w-480" alt="A photo of a Rhodia Unlimited notebook inside a leather case." class="blog_image" title="A photo of a Rhodia Unlimited notebook inside a leather case." />
<figcaption style="text-align:center">The cover has gotten a bit worn out tho.</figcaption>
</picture>
<p>Several months ago I was visiting NYC and had a breakfast appointment with a friend from a summer job. Unfortunately, the city was dealing with some of its <a href="https://www.bbc.com/news/live/world-us-canada-66963276">worst flooding in years</a> that morning. After getting stuck in a bus inside Central Park, I stupidly waded through several waist high flooded tunnels to make it to my appointment (I was still late by 1+ Hour). In doing so I killed a portable battery I had with me and my iPhone started boot looping (so much for being waterproof). My Rhodia notebook was perfectly fine though! There is zero trace of water damage to the pages which is just astonishing considering what they went through.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_tunnel_photo_75SWjN09P.jpeg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_tunnel_photo_75SWjN09P.jpeg?tr=w-480" alt="A photo of a Rhodia Unlimited notebook inside a leather case." class="blog_image" title="A photo of a Rhodia Unlimited notebook inside a leather case." />
<figcaption style="text-align:center">Not my proudest moment.</figcaption>
</picture>
<p>My other notebook isn’t quite so great. It’s a <a href="https://pencils.com/products/forestchoice-small-flex-notebook-triple-set?variant=23948024053860">ForestChoice notebook with squared paper</a>, and if I’m being honest I wouldn’t recommend it. It’s not bad, but ink bleeds through it more than I would like. Apparently it uses extra special “forest friendly” paper (it’s not recycled tho) but that doesn’t make it worth it in my eyes.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1202_LgxSuFEAPu.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-28-what-i-carry-in-my-pockets/_IMG_1202_LgxSuFEAPu.jpg?tr=w-480" alt="A photo of the inside of a ForestChoice notebook." class="blog_image" title="A photo of the inside of a ForestChoice notebook." />
<figcaption style="text-align:center">I like using this notebook to plan out things.</figcaption>
</picture>
<h2 id="conclusion">Conclusion</h2>
<p>To round things out, I keep my back left pocket empty. Sometimes I put a wallet in there, but I prefer not to. I’m a believer in always leaving extra space/resources for whatever might arise.</p>
Julian Lopez<h2 id="phone-stuff">Phone Stuff</h2>
Setting Up My Domain2023-11-20T00:00:00Z2023-11-20T00:00:00-08:00https://www.julianlopez.net/posts/2023/11/setting-up-my-domain
<h2 id="why-did-i-buy-a-domain">Why did I buy a domain?</h2>
<p>Recently I decided to purchase a domain through AWS Route 53 for the purpose of making connecting to my server at home easier. Before I bought this domain whenever I had to connect to the stuff I have hosted on there (RSS feeds/media server/torrenting/etc) I had to type out my entire IP address. This is obviously a pain to do multiple times per day, and there are certain services/apps that don’t work well with just IP addresses. Thus, I decided to pay $11 per year for this domain (<code class="language-plaintext highlighter-rouge">julianlopez.net</code>).</p>
<p>Having it point towards my home server was super easy, all I had to do was create an A record in my DNS records with no subdomain and the value being my server IP address. After I did that, it worked perfectly! All I had to do in order to connect to my server via SSH was just type in the domain and login info and it worked!</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-20-setting-up-my-domain/images_route_53_XOmB4z2P6.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-20-setting-up-my-domain/images_route_53_XOmB4z2P6.png?tr=w-480" alt="A screenshot of an AWS Route 53 A record." class="blog_image" title="A screenshot of an AWS Route 53 A record." />
<figcaption style="text-align:center">Don't put anything for the subdomain and set your server's IP address as your value.</figcaption>
</picture>
<h2 id="subdomains-are-awesome">Subdomains are awesome!</h2>
<p>However, I got inspired by <a href="https://chriscoyier.net/2023/09/21/use-subdomains/">a post by Chris Coyier</a> to try using subdomains to better organize and keep track of all the stuff I have running on ports off my server. Plus, there was one time that I tried showing said stuff to a friend while at their place, but I completely blanked out on most of my port numbers! I wasn’t able to show them much… Never again!</p>
<p>Af first, I was at a complete loss at how to do this. I was able to create subdomains within the AWS console, but I couldn’t route them to my server. Eventually I figured out that within DNS records you can only have an IP address, you can’t have an IP address <em>and</em> port number there. Instead what you have to do is create A records for your desired subdomain and have them point to the exact same IP address as the initial A record.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-20-setting-up-my-domain/images_hosted_zone_kJQN4YkWZ.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-20-setting-up-my-domain/images_hosted_zone_kJQN4YkWZ.png?tr=w-480" alt="A screenshot of an AWS Route 53 hosted zone's records." class="blog_image" title="A screenshot of an AWS Route 53 hosted zone's records." />
<figcaption style="text-align:center">Despite these A records all having different subdomains, they all point to the same IP address.</figcaption>
</picture>
<p>Now all these subdomains were being routed properly to my server, but once at the server they were not being routed to the port they needed to use. For that I had to set up Nginx to properly forward my requests to my port of choice.</p>
<p>Within the http section of my Nginx config (on my Ubuntu server its filepath is <code class="language-plaintext highlighter-rouge">/etc/nginx/nginx.conf</code>) I added code similar to what I have below to redirect requests from port 80 (the default port web browsers try to connect to) to the appropriate port. <code class="language-plaintext highlighter-rouge">server_name</code> is just the subdomain plus domain.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http{
...
server {
listen 80;
server_name subdomain_one.julianlopez.net;
location / {
proxy_pass http://localhost:69;
}
}
server {
listen 80;
server_name subdomain_two.julianlopez.net;
location / {
proxy_pass http://localhost:420;
}
}
}
</code></pre></div></div>
<p>After restarting Nginx (I ran <code class="language-plaintext highlighter-rouge">/etc/init.d/nginx restart</code> as root), I no longer had to type in port numbers when accessing my stuff! I was initially concerned that switching to subdomains might break some functionality, but everything worked perfectly.</p>
<h2 id="making-my-blog-cooler">Making my blog cooler</h2>
<p>I could have my blog accessible through my domain through Nginx served off my server since it’s a static Jekyll site. However, I like using GitHub Pages for for my site hosting since it provides SSL certificates without having to do anything extra. Additionally, I like the idea of showing off my site assets (HTML/CSS/JS) if anyone wants to copy something I made. Thankfully, GitHub Pages allows you to use your domain along with a subdomain to host your website. All you have to do is verify your domian via DNS records, then add a filenamed <code class="language-plaintext highlighter-rouge">CNAME</code> containing your subdomain and domain (in my case: <code class="language-plaintext highlighter-rouge">https://www.julianlopez.net/</code>)</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-20-setting-up-my-domain/images_github_verification_gfrDCSX-9.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/www_julianlopez_net/2023-11-20-setting-up-my-domain/images_github_verification_gfrDCSX-9.png?tr=w-480" alt="A screenshot of the GitHub page to verify ownership of your domain." class="blog_image" title="A screenshot of the GitHub page to verify ownership of your domain." />
<figcaption style="text-align:center">Create a TXT record with the string from 1. as your subdomain and the string from 2. as the value of your record.</figcaption>
</picture>
<p>If you want to host more than one website on your same GitHub account you just need to repeat all these steps, but also change the url in your Jekyll <code class="language-plaintext highlighter-rouge">_config.yml</code> file to your subdomain and domain.</p>
<h2 id="what-about-the-root-domain">What about the root domain?</h2>
<p>At this point, when I put <code class="language-plaintext highlighter-rouge">julianlopez.net</code> into my web browser I just got a page from Nginx. This seemed like a waste of this URL, plus people trying to access my blog probably wouldn’t type in the <code class="language-plaintext highlighter-rouge">www.</code> part. To fix both of these problems I decided to have my server route all requests for my root domain ot my</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
server_name julianlopez.net;
return 301 https://www.julianlopez.net;
}
</code></pre></div></div>
<p>I was worried that this might reroute ALL requests to my server (including SSH) but this is not the case. It only reroutes web traffic (port 80 stuff) so I have nothing to be worried about.</p>
<h2 id="conclusion">Conclusion</h2>
<p>At first, this was all beyond daunting to even attempt but this all now feels super easy to set up! I believe the lack of proper documentation and explainers for some of these topics (especially setting up multiple sites on GitHub Pages) contributes towards making this all look hard.</p>
<p>In the future I might look into having Nginx run via docker so that I can manage it in Portainer alongside all the other containers I have running, but I’m concerned about how that might work with SSL encryption via Let’s Encrypt.</p>
Julian Lopez<h2 id="why-did-i-buy-a-domain">Why did I buy a domain?</h2>
Am I Worth My Tools?2023-11-10T00:00:00Z2023-11-10T00:00:00-08:00https://www.julianlopez.net/posts/2023/11/am-i-worth-my-tools
<p>I’ll be the first to admit, I don’t exactly have access to the best tools for my projects. The laptop I used to use has a crappy Intel Pentium processor with 4 GB of RAM, but I often use an 8th gen iPad now for most of my Tech needs. That said, I view this as less of a detriment but more of an opportunity to learn how to maximize the tools at my disposal. If I had a full fat laptop with all the power/storage/memory I could ever want I wouldn’t have learned certain skills that I’ve picked up. For instance, there are plenty of things that you simply cannot do on an iPad. In order to get around this, I’ve set up virtual machines (Windows 10 / Endeavor OS) on my home server that I can remote into with Anydesk. Now I can do anything that can be done on a desktop from a thin and mobile iPad! I turned this weakness into an opportunity to learn and grow my personal skill set, which can help me in my future career.</p>
<p>That said, I have a certain friend with the opposite mindset of mine. What he does is go out and purchase the best equipment possible for whatever it is he is working on. For his Adobe Lightroom projects he doesn’t bat an eye at blowing huge amounts of cash on laptops with 64 GB of RAM and multiple terabytes of NVMe storage. A more… extreme example of his mindset was his decision to purchase $1000 fountain pen. In order to write well he should only use the best writing tools!</p>
<p>In a way, I suppose my personal belief on this topic can be explained by a concern of worth. “Am I worth this amazing new gadget?” in the case of my home server(her name is Izumi), I initially didn’t feel this way. However, this concern faded away as I slowly pushed her more and more to her limits. Now, as I have multiple VMs / Docker containers / a GitLab instance / media sharing via Jellyfin / and a bunch more, I no longer feel these concerns of worth. Instead, I am now concerned by how to upgrade and expand my horizons further!</p>
Julian Lopez<p>I’ll be the first to admit, I don’t exactly have access to the best tools for my projects. The laptop I used to use has a crappy Intel Pentium processor with 4 GB of RAM, but I often use an 8th gen iPad now for most of my Tech needs. That said, I view this as less of a detriment but more of an opportunity to learn how to maximize the tools at my disposal. If I had a full fat laptop with all the power/storage/memory I could ever want I wouldn’t have learned certain skills that I’ve picked up. For instance, there are plenty of things that you simply cannot do on an iPad. In order to get around this, I’ve set up virtual machines (Windows 10 / Endeavor OS) on my home server that I can remote into with Anydesk. Now I can do anything that can be done on a desktop from a thin and mobile iPad! I turned this weakness into an opportunity to learn and grow my personal skill set, which can help me in my future career.</p>
How I Listen To Music2023-10-26T00:00:00Z2023-10-26T00:00:00-07:00https://www.julianlopez.net/posts/2023/10/how-i-listen-to-music
<p>Growing up as a Kid I loved listening to anime music on my iPod. I started out by purchasing songs off of iTunes for $0.99, but there weren’t that many songs on there from shows that I liked. (In hindsight, they might have had them but with Japamese titles which I couldn’t read/search.) The one place I was able to easily find these songs was on YouTube so I used that as my source. I would grab the URLs I wanted and go visit some sketchy YoaTube to MP3 websites, import the MP3s into iTunes, then sync my iPod.</p>
<p>Over a decade later and the way I listen to my music has not fundamentally changed. I used Apple Music / Spotify for a while but the music selecton still wasn’t great for me especially for Video game soundtracks. YouTube Music was almost pertect but I had issues with certain tracks being removed and readded from listening availibilty. Thus I’ve stuck to transferring MP3s to my phone although I’ve made a few improvements on the overall process.</p>
<p>I have a bash script that a cron job runs periodically which syncs my YouTube playlists and the music on my server. This scipt also adds Album name metadata using eyeD3 which I have match the playlist titles. This way, I can easily sort the music in my Ilbrary without having to resort to creating playlists.</p>
Julian Lopez<p>Growing up as a Kid I loved listening to anime music on my iPod. I started out by purchasing songs off of iTunes for $0.99, but there weren’t that many songs on there from shows that I liked. (In hindsight, they might have had them but with Japamese titles which I couldn’t read/search.) The one place I was able to easily find these songs was on YouTube so I used that as my source. I would grab the URLs I wanted and go visit some sketchy YoaTube to MP3 websites, import the MP3s into iTunes, then sync my iPod.</p>
Good Customer Support2023-08-31T00:00:00Z2023-08-31T00:00:00-07:00https://www.julianlopez.net/posts/2023/08/good-customer-support
<p>Having to make a phone call and talk to a companies customer support always sucks. Nowhere has this been more apparent to me than when I have been on hold for over an hour to talk to my university’s financial aid department. However, there have been some rare instances where I found my experiences almost enjoyable.</p>
<h2 id="consumer-cellular">Consumer Cellular</h2>
<p>Several years ago I was helping a guy out. He got mugged and had all of his possession stolen. I decided to give him an old phone of mine, but we needed to transfer his phone number to it. So we had to call his cellular provider, consumer cellular to do so. Keep in mind, prior to this the two of us had made multiple excruciating phone calls, over the better part of a month to replace some of his lost possessions. Just to attempt to replace one of these items took multiple days worth of calls and often ended in failure. Thus, you weren’t expecting much from a single car. After a long wait (probably around 30 minutes) the two of us finally got on the line with someone. Immediately I knows this person had a southern accent which of reassuring since it meant I was not dealing with an international call center (which have never provided good service in my experience). Two are shocked and surprised, within 10 minutes we managed to get the number transferred! This is so unexpectedly quick I just had to think the representative on the phone for how great the service was.</p>
<h2 id="nintendo-of-america">Nintendo of America</h2>
<p>As I mentioned in the previous post, I recently bought myself a used Nintendo 3DS. However, when I attempted to use my Nintendo account to access the eShop (this was before closure) I was blocked from doing so because the account of its previous owner was still tied to the console. The procedure for removing that account involved making a phone call to a Nintendo of America line for 3DS inquiries, and have a representative Remove it for me. To my surprise, not only was this line still active years after the 3DS had been discontinued (this was probably in 2021), but there was hardly any wait time to speak to someone. The person I then spoke to was super chill and completely understood why I purchased “outdated” console (purely for nostalgia). After I was done with that call, I made sure to give that representative a glowing review on the email questionnaire I was later sent.</p>
<h2 id="amazon-web-services">Amazon Web Services</h2>
<p>To this day, this is the most incredible customer support experience I’ve ever had. Back in my final year of high school, I was experimenting with making an inventory app for a club I created to donate computers to low income families. Of course, I had no clue I was doing so at one point I accidentally pushed AWS IAM credential info to GitHub. Within 24 hours I got a call from the Seattle number. To my shock and awe, it was an AWS support employee who had called to inform me that they had noticed that keys tied to my account were publicly viewable on GitHub and they had deactivated them to protect my account. Suffice to say, my 18 year old mind was blown. I have issues with the way Amazon and their cloud services division sometimes conduct business, but the incredible support I received from them on that day will always stick with me and be a driving reason why I use their services.</p>
Julian Lopez<p>Having to make a phone call and talk to a companies customer support always sucks. Nowhere has this been more apparent to me than when I have been on hold for over an hour to talk to my university’s financial aid department. However, there have been some rare instances where I found my experiences almost enjoyable.</p>
Finding Flags on a Website2023-07-30T00:00:00Z2023-07-30T00:00:00-07:00https://www.julianlopez.net/posts/2023/07/finding-flags-on-a-website
<p>A while back, I was on a website that had a weird link near the bottom that was titled “Capture the Flag”. Clicking on it, directed me to a “secret” page that described how there were six hidden flags throughout the site with in format “GXYZ{***}”. If you managed to find a flag, you could have your name added to a “hall of fame” along with the number of flags you had found.</p>
<p>Coincidentally, earlier that day I had come across a blog post that had something to do with storing data within image files. On a hunch, I download an image of a flag that was on that page and opened it in Vim. To my pleasant surprise, at the end of the file there was a flag! Unfortunately I haven’t found any other flags yet, but I haven’t been trying that hard.</p>
<p>I won’t be linking to this website since it would be unfair as I’ve already detailed one of the flags. That being said, a quick web search (Bing in my case) will result in many similar challenges open to all.</p>
Julian Lopez<p>A while back, I was on a website that had a weird link near the bottom that was titled “Capture the Flag”. Clicking on it, directed me to a “secret” page that described how there were six hidden flags throughout the site with in format “GXYZ{***}”. If you managed to find a flag, you could have your name added to a “hall of fame” along with the number of flags you had found.</p>
Cleaning My 3DS2023-05-16T00:00:00Z2023-05-16T00:00:00-07:00https://www.julianlopez.net/posts/2023/05/cleaning-my-3ds
<h2 id="table-of-contents">Table of contents</h2>
<ul>
<li><a href="#weird-problems-with-my-3ds">Weird Problems with my 3DS</a></li>
<li><a href="#cleaning-the-3ds">Cleaning the 3DS</a></li>
<li><a href="#a-new-sd-card">A new SD Card</a></li>
<li><a href="#footnotes">Footnotes</a></li>
</ul>
<h2 id="weird-problems-with-my-3ds">Weird Problems with my 3DS</h2>
<p>Ever since I bought my 3DS from a retro game store<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, I’ve been having some weird issues with it.
After playing a game for a while (10 minutes+), the system would freeze and I’d get an error on the bottom screen.
At first I thought this was tied to the homebrew/firmware I had installed, but I couldn’t find anything online regarding similar behavior.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post3/IMG_3810.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post3/IMG_3810.jpg?tr=w-480" alt="A Nintendo 3DS with a crash screen" class="blog_image" title="A Nintendo 3DS with a crash screen" />
<figcaption style="text-align:center">This is what a crash would look like.</figcaption>
</picture>
<p>Additionally it only had a 1 in 3 chance of turning on when you pressed the power button.
Removing the SD card and reinserting it seemed to help, but that might have been a placebo.
There were times were it look me upwards of 5 minutes to turn it on, which was especially annoying after a crash.</p>
<p>On top of this, removing the SD card was a pain since the cover for the SD card slot almost never closed properly.
As a result the system would often not recognize the SD card which prevented it from booting with homebrew.
This was also just annoying at a practical level since I had to carry around my 3DS with the SD card cover slightly open.</p>
<h2 id="cleaning-the-3ds">Cleaning the 3DS</h2>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post3/IMG_3797.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post3/IMG_3797.jpg?tr=w-480" alt="A Nintendo 3DS with the back removed" class="blog_image" title="A Nintendo 3DS with the back removed" />
<figcaption style="text-align:center">Take a good look around the screw holes.</figcaption>
</picture>
<p>Removing the back of the 3DS (which only took 4 phillips screws) revealed yet another problem.
There was some sort of yellowish residue around the screw holes, which was also present in between the “seams” on the bottom of the 3DS.
My best guess is that at some point the previous owner (probably a dumb kid) spilled something on it which might have damaged/broken it and sold it to the store I bought it from.
They then probably repaired it, but didn’t do a great job of cleaning it and only did the bare minimum to get it working.
Credit to that store though, they gave me a free warranty so I could have gotten it fixed for free, but given that I hacked it and was running homebrew I didn’t want to push my luck.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post3/IMG_3800.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post3/IMG_3800.jpg?tr=w-480" alt="The exposed SD card slot of a Nintendo 3DS with gunk in it" class="blog_image" title="The exposed SD card slot of a Nintendo 3DS with gunk in it" />
<figcaption style="text-align:center">A look at the gunk in the SD slot.</figcaption>
</picture>
<p>Disassembling it further revealed that the SD card slot was also full of this gunk.
This was causing extra friction with the SD card which was why it was so hard to close the cover.
The fact that this gunk was also present here makes me think that this 3DS was submerged in some sort of liquid.
That it survived at all is probably a miracle.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post3/IMG_3803.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post3/IMG_3803.jpg?tr=w-480" alt="A clean disassembled Nintendo 3DS" class="blog_image" title="A clean disassembled Nintendo 3DS" />
<figcaption style="text-align:center">The finished result.</figcaption>
</picture>
<p>It took me several hours, but I got rid of any trace of the gunk.
Unfortunately, I didn’t have any rubbing alcohol (and I wasn’t crazy enough to use water) so I had to use a bunch of disposable alcohol wipes and just rub the plastic as hard as I could.
I didn’t want to touch any of the electronic stuff, but I noticed that the game cartridge slot might have had some signs of corrosion.
In the future I’ll probably try to clean that out as well, but for now I’m just happy that my 3DS is working again.</p>
<h2 id="a-new-sd-card">A new SD Card</h2>
<p>When I first hacked my 3DS I used a 128GB SD card I had been using for my Switch.
The idea was to have all the games I could ever possibly want installed on my 3DS.
However, this isn’t a great idea since the 3DS can only use 32GB SD cards by default.
While it can use larger SD cards, it generally becomes slower the larger the SD card is.
My suspicion is that the reason my 3DS was crashing was because of how slow the SD card was.</p>
<p>Thankfully I have a friend who traded me a 32GB SD card for my 128GB one.
All I had to do to use it with my 3DS was format it to FAT32 and copy over the files from my old SD card.
The only hard part about this was that I had to delete a bunch of games to make it fit on the 32GB card.
After that it worked perfectly and I haven’t had any crashes since!</p>
<p>Now my only problem is that I promised him I’d trade my 128GB card for it and I’ve since lost it!</p>
<h2 id="footnotes">Footnotes</h2>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>GameHogs in East Los Angeles. They have by far the sketchiest storefront I’ve ever been inside, but the interior is amazing. I’ve never seen such a large selection of games, much less retro games! Highly recommend if you’re in the area. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Julian Lopez<h2 id="table-of-contents">Table of contents</h2>
<ul>
<li><a href="#weird-problems-with-my-3ds">Weird Problems with my 3DS</a></li>
<li><a href="#cleaning-the-3ds">Cleaning the 3DS</a></li>
<li><a href="#a-new-sd-card">A new SD Card</a></li>
<li><a href="#footnotes">Footnotes</a></li>
</ul>
Generating Fake McDonald's Screenshots With AWS and OpenAI2023-05-01T00:00:00Z2023-05-01T00:00:00-07:00https://www.julianlopez.net/posts/2023/05/fake-mcdonalds-screenshots
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post2/banner.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post2/banner.jpg?tr=w-480" alt="The McDonald's app" class="blog_image" title="The McDonald's app" />
<figcaption style="text-align:center">Honestly the deals you can get through points are amazing.</figcaption>
</picture>
<h2 id="table-of-contents">Table of contents</h2>
<ul>
<li><a href="#my-problem">My Problem</a></li>
<li><a href="#generating-images-in-the-cloud">Generating Images in the Cloud</a></li>
<li><a href="#making-the-canvas">Making the Canvas</a></li>
<li><a href="#its-all-in-the-details">It’s all in the details</a></li>
<li><a href="#chatgpt-can-do-almost-anything">ChatGPT can do (almost) anything</a></li>
<li><a href="#training-a-custom-gpt-3-model">Training a custom GPT-3 model</a></li>
<li><a href="#drawing-it-all-together">Drawing it all together</a></li>
<li><a href="#apple-shortcuts-is-awesome">Apple Shortcuts is awesome</a></li>
<li><a href="#the-final-product">The final product</a></li>
</ul>
<h2 id="my-problem">My Problem</h2>
<p>Several months ago, I had a dumb first world problem.
Typically my mom likes to order food from McDonald’s using the app, that way she gets points she can redeem for free food. However, in order to pick up at the counter you need to show the order confirmation screen on your phone.</p>
<p>She (being my mother) would then force me to take her phone and pick up the order for her.
I don’t mind being the one to pick up the food, but I don’t like having to use her phone to do it.</p>
<p>If only there was a way I could make a fake screenshot of the McDonald’s app with the her order info in it…</p>
<h2 id="generating-images-in-the-cloud">Generating Images in the Cloud</h2>
<p>A loooong time ago, I made an inventory system built on AWS for a community service thing that donated computers to low income individuals/families.
The main thing it was designed to keep track of was all of the computers that we received/refurbished/donated.</p>
<p>Initially, in order to tell which computer was which, we placed masking tape and wrote on them with sharpies.
However, people’s (my) handwriting sucked so you often come across many computers with illegible ID numbers.
To fix this I wanted to have an app where you could create an entry for a computer and enter in all of its specs and other relevant information.
Then it would create a PNG with an ID number and a QR code that could be printed on a label and stuck on the computer.</p>
<p>In order to do this, I made an Android app that would create a new entry in a DynamoDB database with all of the appropriate fields.
Then the app would trigger a Lambda function that would generate the PNG using information from that entry (ID number and computer type), and upload it to an S3 bucket where it could be accessed elsewhere. Looking back on this, I hate this and I am glad that I don’t have any of this code anymore.</p>
<figure>
<img src="https://mermaid.ink/img/pako:eNpFkMtuwjAQRX9lNCsqwYpdFpVCjNiQijaswF0M8QQs4oeMoyoi_DsmUDGreZzRvbpXrJ1izLBp3V99ohBhK6SFVPk-tyo4rSD3_hdms8-hCEyRYVPA0sbQD7CYiN6ScWLx8XoauZLODN8_sPlaDVBM1mQOil5EMRJVdOGNJMXnUeyr-SgFg9AX31L_z-Q4RcPBkFbJ7fWBS4wnNiwxS63ihro2SpT2llDqoqt6W2MWQ8dT7LxKzoWmYyCDWUPtJW092Z1z75mVTr7KZyJjMLc7mIZblg?type=png" alt="Diagram of AWS backend" />
<figcaption style="text-align:center">I'm going off my memory here, so this is probably wrong.</figcaption>
</figure>
<p>Fundamentally, generating a fake McDonald’s screenshot would be much simpler than this since I don’t need to deal with any of the database stuff.
However, unlike these labels which are just text on a white background, I’d need to have a background image and place text on top of it.</p>
<h2 id="making-the-canvas">Making the Canvas</h2>
<p>First I ordered an Oreo McFlurry from a McDonald’s with my phone and took a screenshot of the order confirmation page.
I then imported it into GIMP, erased a bunch of stuff within it, and split it into two images, one for the top half and one for the bottom half.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post2/top_half.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post2/top_half.jpg?tr=w-480" alt="" class="blog_image" title="" />
<figcaption style="text-align:center"></figcaption>
</picture>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post2/bottom_half.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post2/bottom_half.jpg?tr=w-480" alt="" class="blog_image" title="" />
<figcaption style="text-align:center">It's weird seeing so much blank space in this image</figcaption>
</picture>
<p>The reason I split it into two images was because I didn’t to have a limit to how many items I could have in the order.
If I had stuck with just the original screenshot, the order text could have gone off the bottom of the screen so I figured stitching two images together would be an easy fix.</p>
<h2 id="its-all-in-the-details">It’s all in the details</h2>
<p>I initially kept the time in the upper left cover, but if I tried ordering at night and the time was 1:00 PM it could potentially give me away.
Luckily, Apple really likes using “Helvetica” in their software so I was able to easily download a ttf file and use it to generate the time.</p>
<p>The rest of the text was not so easy to fake.
I used an online text analyzer to figure out what font McDonald’s uses, and it wasn’t able to nail it down 100%.
Additionally, all of the fonts it was suggesting were paid fonts, so I couldn’t just download them.
After some trial and error I settled on “Heebo Black” which isn’t a perfect match, but it’s close enough for a brief glance.
If anyone were to take a closer look in comparison to the real app this would probably be the first thing they notice.</p>
<p>Thankfully, because I used Apple Pay when I placed my order, I didn’t have to worry about providing a real debit card number.
Without getting too into it, my understanding is that Apple Pay generates a different card number for each transaction.
Thus I was able to just use a random number generator to generate a four digit number and use that as the card number.</p>
<p>However, the toughest issue was the cost of the order which I needed a way to guess.</p>
<h2 id="chatgpt-can-do-almost-anything">ChatGPT can do (almost) anything</h2>
<p>The answer (of course) was to use AI!</p>
<p>Prior to this project, I had been screwing around with OpenAI’s APIs and they are shockingly easy to work with.
Plus, they’re super cheap!</p>
<p>To oversimplify a bit, the newer an AI model is the better it is.
When I started working on this project OpenAI had released an endpoint for a model called GPT-3.5 Turbo intended for chat (which I think is what ChatGPT uses).
(Now they are up to GPT-4)
Since that was the best model they had available at that time, I decided to use it.</p>
<p>I got it working pretty quickly, but there were some serious problems.
For one, it wasn’t very good at pricing things.
Multiple queries with the exact same prompt would yield wildly different results.
When guessing how much a Big Mac cost I would get responces that ranged from $2.99 to $5.99.
This is because McDonald’s prices vary wildly across America, but whenever I tried to specify SoCal/California pricing it just refused to generate a number.</p>
<p>Additionally, no matter what I gave it as a prompt, I couldn’t get it to output in a standardized format.
For instance, I wanted it to output $2.99 as <code class="language-plaintext highlighter-rouge">2.99</code> but I would typically get <code class="language-plaintext highlighter-rouge">$2.99</code>.
No problem, I can easily use <code class="language-plaintext highlighter-rouge">.replace('$', '')</code> to get rid of the dollar sign.
But what was even more frustrating was that I had gotten got outputs like <code class="language-plaintext highlighter-rouge">Your cost would be $2.99</code>, <code class="language-plaintext highlighter-rouge">Total Cost: 2.99</code>, and others like that instead of just the number I wanted.</p>
<p>I could have tried fixed these problems, but I decided to take a different approach towards using the API.</p>
<h2 id="training-a-custom-gpt-3-model">Training a custom GPT-3 model</h2>
<p>Thankfully the chat endpoint wasn’t the only offering OpenAI had with their API.</p>
<p>Something I had been wanting to try for a while was training my own GPT-3 model.
In short, its as easy as making a spreadsheet with a bunch of example inputs and outputs, putting it through an OpenAI JSONL formatter, and then uploading it to the API.</p>
<p>So I spent just over an hour going the McDonald’s app for the location I go to and logged the prices for almost everything there.
After that I uploaded the data to the API and it took just shy of 30-45 minutes to train.
The longest part wasn’t the actual training, but waiting in the queue to get my turn to train</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post2/gpt-spreadsheet.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post2/gpt-spreadsheet.png?tr=w-480" alt="" class="blog_image" title="" />
<figcaption style="text-align:center">222 lines of McDonald's.</figcaption>
</picture>
<p>At this point the model I trained was very good at guessing prices for individual menu items.
It was even able to provide the correct price even when I mistyped the name of an item.
However, it still wasn’t able to generate a total price for multiple items.
In order to get around this, I decided to have my code call the API for each item and add each result together.</p>
<p>While I could have added additional training so it could process multiple items at once, I decided not to do that since the API was already pretty fast and this would only shave off a second or two.
It’s not worth it for me to spend an hour plus formating the data for that small of a speed increase.
Plus, in my experience I don’t trust a GPT-3 model to do addition correctly.
While GPT-4 is probably better overall, for my future OpenAI projects I’m going to break up my tasks and combine them with coding instead of trying to do it all in one API call.</p>
<h2 id="drawing-it-all-together">Drawing it all together</h2>
<p>Now that all the data is loaded, it just needs to be drawn on top of the edited screenshots.</p>
<p>Thankfully drawing is super easy in Python using PIL(Pillow).
On my laptop all I had to do was install it with pip, type out a few lines of code, and I was done.
The only hard part was figuring out the coordinates for where to draw the text, but that was just a matter of trial and error.</p>
<p>Unfortunately, it wasn’t this easy to use PIL on AWS Lambda.
Typically (for Python) you bundle your code and its dependencies into a zip file and upload it to AWS.
However, for some reason I couldn’t get my code to run properly on Lambda with its bundled dependencies (in this case PIL).
This could have been a big problem since as far as I know, this is the only way to upload pip dependencies to Lambda.</p>
<p>Thankfully, I was able to get around this by using layers.
In short, someone else had already bundled PIL into a zip file and uploaded it to AWS.
With the ARN of that layer, I was able to use it in my Lambda function without having to bundle it myself.
If it weren’t for this guy I would have been kinda screwed.</p>
<p>Overall Azure Functions are a lot easier to work with since you can actually prepackage your code with its dependencies and upload it directly to Azure within VS Code.
For this and other reasons, I might consider redeploying this project on Azure in the future.</p>
<h2 id="apple-shortcuts-is-awesome">Apple Shortcuts is awesome</h2>
<p>Having a script that can generate a fake McDonald’s order is cool, but it’s not very useful if I have to run it on my laptop every time I want to use it.</p>
<p>Luckily I only had to develop for iOS since it’s what my phone runs and I’m the only one who’s ever going to use this.
Unfortunately, I don’t have a Mac so I can’t use Xcode to develop an app.
Plus, back then I wasn’t as knowledgeable about web development as I am now.</p>
<p>As it turns out, Apple has a built in app called Shortcuts that lets users create/share scripts that can be run from the home screen or with Siri.
Despite the drag and drop interface that is akin to Scratch, it is surprisingly powerful and has access to many system features.
For the purposes of this project, it is able to make HTTP requests and save images locally.</p>
<figure>
<img src="https://mermaid.ink/img/pako:eNpVkEFrwzAMhf-K8Lk5beyQwyBpt15WCCRQWN2DaiuNIbZTR2aUJP997nLYppMkvif03iSU1yRy0fb-S3UYGJqddJCqOJmq846g7nxgFfkMWfYKc8c8wP6tgUC3SCPPUE7FsYYPtBeNUrrqzkkH79EpNt4t67lyVRsmCw4tzbA9NQGNIw37qsme4JA-6c8rvf1DD8GohJf_7lxwJHh5BnIPA3MhNsJSsGh0MjM9UCm4I0tS5KnV1GLsWQrploRiZF_fnRI5h0gbEQeNTDuD14BW5C32Y9oO6D69_51JG_bhsAb2k9vyDa7BaUA?type=png" alt="Diagram of screenshot generation" />
<figcaption style="text-align:center">Honestly this is pretty simple.</figcaption>
</figure>
<p>So I set up mmy script which asks for the name of the person who placed the order, the items they ordered, and what their order code was.
Then it appends this data to a URL and makes a GET request to the AWS Lambda function I set up earlier.
From there it downloads the image and saves it to the photos app.</p>
<h2 id="the-final-product">The final product</h2>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post2/1D99F7A8-6145-492B-9ED4-5A365A12DA81.jpeg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post2/1D99F7A8-6145-492B-9ED4-5A365A12DA81.jpeg?tr=w-480" alt="" class="blog_image" title="" />
<figcaption style="text-align:center">A 100% fake screenshot.</figcaption>
</picture>
<p>And with that I was done.
I had a means to fake McDonald’s screenshots on my phone in order to not use my mom’s phone.
All that was left was to use it in action…</p>
<p>That Saturday I had my mother place an order off of her phone so that I could pick it up using only what I had made.
I then walked up to the counter more anxious than I had ever been picking up a Big Mac.
The person behind it then barely gave my phone a glance before handing me my order.
Success!</p>
<p>Given this response, if I so desired I could easily use this to get free food and steal from McDonald’s and its patrons.
However, I am not a criminal and have chosen to never do this.
In order to avoid encouraging such bad behaviors (and so that I don’t get sued) I haven’t posted the full code for this project on GitHub.
Instead, I only pushed the code and assets for the image generation and the OpenAI API call, the AWS Lambda function, and the Apple Shortcut is not included.
If someone so desired, they could probably easily replace those missing parts with their own code.
That being said, if you have the know-how to do so, you probably have better things to do.</p>
<h2 id="the-obvious-easy-solution-to-my-dumb-problem">The (Obvious) Easy Solution to my Dumb Problem</h2>
<p>Of course, I immediately set about bragging about what I made to anyone I knew.
One person I told was a friend of mine who is a nurse and didn’t fully understand what I was talking about.
That being said, she asked a very simple question that I couldn’t answer.</p>
<p>“Why couldn’t you ask your mom to send you a screenshot?”</p>
<p>I was dumbfounded.
On this same line of thought, why did I have to create a way for this code to guess the price?
I could have easily added a field for me to input the price in the shortcut and it would’ve eliminate the need to use the OpenAI API.
However, in hindsight there was a simple answer to this question.</p>
<p>“Why not?”</p>
Julian Lopez<picture>
<source srcset="https://ik.imagekit.io/jlo64/post2/banner.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post2/banner.jpg?tr=w-480" alt="The McDonald's app" class="blog_image" title="The McDonald's app" />
<figcaption style="text-align:center">Honestly the deals you can get through points are amazing.</figcaption>
</picture>
Hacking My Nintendo 3DS2023-04-11T00:00:00Z2023-04-11T00:00:00-07:00https://www.julianlopez.net/posts/2023/04/hacking-game-consoles-part-i
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/nintendo3ds-white-back.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/nintendo3ds-white-back.jpg?tr=w-480" alt="An aqua-blue Nintendo 3DS with a stylus on a white background" class="blog_image" title="An aqua-blue Nintendo 3DS with a stylus on a white background" />
<figcaption style="text-align:center">My childhood in a nutshell.</figcaption>
</picture>
<h2 id="table-of-contents">Table of contents</h2>
<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#hacking-explained">Hacking explained</a></li>
<li><a href="#hacking-a-3ds">Hacking a 3DS</a></li>
<li><a href="#homebrew-3ds-apps">Homebrew 3DS Apps</a></li>
<li><a href="#emulating-old-games">Emulating Old Games</a></li>
<li><a href="#the-piracy-issue">The Piracy Issue</a></li>
<li><a href="#should-you-buy-a-3ds-in-2023">Should you buy a 3DS in 2023</a></li>
</ul>
<h2 id="introduction">Introduction</h2>
<p>As weird as it sounds to say this, if you have a Nintendo 3DS you should try hacking it!
And I’m not suggesting you do this just to pirate games.
But before I get into that let me give you a bit of a personal backstory.</p>
<p>As a pre-teen, I grew up with my favorite gadget in the world, my aqua-blue 3DS.
I got it in 2011 (the year it came out) and back then it blew my mind that something so capable could fit in my pocket.
That was right before the first price drop (from $250 to $170), so to compensate consumers who paid full price they introduced the “Ambassador Program” which let members download several Gameboy Advance games for free!f
That in conjunction with all the great games that came out for it made it a perfect distraction from the real world.</p>
<p>However in 2013, I lost it while meeting up with a friend of mine at Central Park in New York City!
I was devastated, but thankfully my mother ended up buying me an XL model later that year.
Years after the fact I came across a post on an obscure forum from someone who found an aqua-blue 3DS at that same location that matched the description of mine…</p>
<p>Fast forward to 2021, and I was at a really cool retro game store in East LA called GameHogs.
I was trying to find a launch PS3 when I came across the exact same model of 3DS I had growing up as a kid!
I had to buy it, partially out of a sense of nostalgia, but also because I knew that if I hacked it I could do some really cool stuff with it.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/my-3ds.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/my-3ds.png?tr=w-480" alt="an aqua-blue 3DS being held" class="blog_image" title="an aqua-blue 3DS being held" />
<figcaption style="text-align:center">She's as beautiful as the day I lost her.</figcaption>
</picture>
<h2 id="hacking-explained">Hacking explained</h2>
<p>Let’s get this out of the way though, hacking a game console is not illegal!</p>
<p>Hacking can be defined as opening closed computer systems for functions other than they were designed for, such as homemade or as they’re called in this context “homebrew” software.
Simply put, you bought this gadget so you should be able to do what you want with it!
Honestly I think people call it hacking instead of modding because hacking sounds way cooler.</p>
<p>Generally, there are two types of hackers (within console hacking): pirates who want to play games for free, and enthusiasts who want to do cool stuff with their consoles.
These two groups are often at odds with each other, but their goals overlap in wanting unrestricted access to their hardware.</p>
<h2 id="hacking-a-3ds">Hacking a 3DS</h2>
<p>I’m not going to get too deep into the details of how to hack a 3DS, this isn’t meant to be a tutorial and the exact methods are always changing.
That being said, you can visit <a href="https://3ds.hacks.guide">3ds.hacks.guide</a> for the most up to date information on how to do so.
What I will cover are some of the apps you can install and what they bring to the table.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/3ds-hacks-guide.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/3ds-hacks-guide.png?tr=w-480" alt="a screenshot of the 3ds.hacks.guide website" class="blog_image" title="a screenshot of the 3ds.hacks.guide website" />
<figcaption style="text-align:center">All you need to do is follow the steps listed on here and you'll be good to go.</figcaption>
</picture>
<p>First off, installers that allow you to install apps directly to the homescreen end with the extension “.cia”.
So of course, the app you use to install these files is called <a href="https://github.com/Steveice10/FBI">FBI</a>.
With this app, you can either install app from files on your SD card, or you can scan a QR code
Apps that have their source code posted on github often have these QR codes as well.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/fbi-qr.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/fbi-qr.png?tr=w-480" alt="a screenshot of the FBI app scanning a QR code" class="blog_image" title="a screenshot of the FBI app scanning a QR code" />
<figcaption style="text-align:center">This is by far the coolest feature I've ever seen built into homebrew!</figcaption>
</picture>
<p>However, you don’t have to use this to install all of your software.
The app <a href="https://github.com/Universal-Team/Universal-Updater">Universal Updater</a> acts as a sort of 3DS app store with plenty of new apps and updates for them being posted on there.
It’s a super easy way to not only download homebrew apps and games but keep them updated without having to deal with file management.</p>
<h2 id="homebrew-3ds-apps">Homebrew 3DS Apps</h2>
<p>My favorite homebrew game you can install from there is based off of a fairly popular one. Wordle DS!</p>
<p>It’s surprisingly convenient having two screens to play it on and what’s even better is that it uses the same list of words as the official version!
I’ve often followed the development of this port on <a href="https://gbatemp.net/threads/release-wordle-ds-a-clone-of-wordle-for-the-ds-i.607796/">GBAtemp</a> where the developer frequently posts updates and fun little tidbits about this app and the New York Times version of Wordle.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/ds-wordle.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/ds-wordle.png?tr=w-480" alt="a photo of a 3DS running the Wordle DS app with a qr code on the bottom screen" class="blog_image" title="a photo of a 3DS running the Wordle DS app with a qr code on the bottom screen" />
<figcaption style="text-align:center">It even generates a QR code so you can still share your score online.</figcaption>
</picture>
<p>This of course isn’t the only piece of homebrew software I’ve downloaded for my 3DS.
I have <a href="https://github.com/Cam-2002/Minesweeper-3DS">Minesweeper</a>, an app that showcases <a href="https://github.com/memeToasty/3ds_sorting">different sorting algorithms</a>, and a port of a <a href="https://github.com/LukeZGD/DDLC-LOVE">perfectly harmless dating simulator</a> made by the hacker known as 4chan.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/3ds-bad-apple.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/3ds-bad-apple.png?tr=w-480" alt="a photo of the Bad Apple video playing on a 3DS" class="blog_image" title="a photo of the Bad Apple video playing on a 3DS" />
<figcaption style="text-align:center">Of course, you can play Bad Apple on it.</figcaption>
</picture>
<p>Even better, custom themes are a thing! All you have to do is download <a href="https://github.com/astronautlevel2/Anemone3DS">Anemone3DS</a> and use the built in qr code scanner to download themes from the <a href="https://3dsthemes.com/">3DS Theme Shop</a>.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/winxp-theme.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/winxp-theme.png?tr=w-480" alt="a photo of a 3DS with a Windows XP theme" class="blog_image" title="a photo of a 3DS with a Windows XP theme" />
<figcaption style="text-align:center">I have a thing for retro looks.</figcaption>
</picture>
<h2 id="emulating-old-games">Emulating Old Games</h2>
<p>But honestly, my favorite apps are the emulators people have developed for it.</p>
<p>Atari 2600, NES, SNES, Genesis and plenty more retro consoles have emulators developed by fans with insane coding skills.
If you have a model that was released later in the 3DS’s lifespan (which is confusingly called the “New” 3DS), with improved clockspeeds and more RAM, you can even emulate PlayStation One games!</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/3ds-balloon-fight.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/3ds-balloon-fight.png?tr=w-480" alt="a photo of a 3DS running the NES game balloon fight" class="blog_image" title="a photo of a 3DS running the NES game balloon fight" />
<figcaption style="text-align:center">Hands down my favorite game on the NES.</figcaption>
</picture>
<p>Make no mistake, developing software for this is no easy feat.
The smartphone you have in your pocket is orders of magnitude more powerful and easier to develop for.</p>
<p>Also, remember that ambassador program I mentioned near the start of this post?
For some reason, Nintendo never sold any of the GameBoy Advance games they released for that program despite the fact that they already put in the work to create an “emulator” (it’s more complex than that) for those games!
Unless you bought in early like me you couldn’t buy or play any of them.
However, thanks to the efforts of those in the homebrew community, you can now use that same “emulator” to run whatever GBA games you want!</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/3ds-metroid-fusion.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/3ds-metroid-fusion.png?tr=w-480" alt="a photo of a 3DS running the Gameboy Advance game Metroid Fusion" class="blog_image" title="a photo of a 3DS running the Gameboy Advance game Metroid Fusion" />
<figcaption style="text-align:center">Metroid Fusion is still one of the scariest games I've ever played!</figcaption>
</picture>
<h2 id="the-piracy-issue">The Piracy Issue</h2>
<p>To be blunt I’m ok with pirating games for my 3DS, but that’s because its a dead platform and me downloading games in 2023 for it doesn’t take away any potential earning from developers.
However, when I first got this particular 3DS the Nintento eShop was still running so I tried downloading <em>Mario & Luigi: Dream Team</em> which is on the larger side of 3DS games.
No matter what I did I couldn’t get it to download, it would always initiate the download and then fail.</p>
<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/dead-eshop.png?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/dead-eshop.png?tr=w-480" alt="a photo of the Nintendo eShop on a 3DS failing to load" class="blog_image" title="a photo of the Nintendo eShop on a 3DS failing to load" />
<figcaption style="text-align:center">It was fun while it lasted.</figcaption>
</picture>
<p>By contrast, using a pirate site such as <a href="https://hshop.xyz/">hShop</a> in conjunction with FBI I was able to successfully download/install the game.</p>
<p>To be clear, I am not an advocate for piracy, but I do think it’s important to understand the difference between piracy and homebrew.</p>
<h2 id="should-you-buy-a-3ds-in-2023">Should you buy a 3DS in 2023?</h2>
<p>If you don’t care about playing the latest and greatest games and you like to tinker with your stuff, I highly recommend getting a 3DS.
For homebrew I fully recommend getting a “New” 3DS.
It’s more expensive but it’s worth it for the extra power and capabilities.
Honestly, when this model first came out there was almost no reason to buy it over the original versions, but now when it comes to homebrew it’s by far the superior choice.
Personally, I am content with my original 3DS, but that’s mainly because of the nostalgia factor it has for me.</p>
Julian Lopez<picture>
<source srcset="https://ik.imagekit.io/jlo64/post1/nintendo3ds-white-back.jpg?tr=w-720,f-webp," type="image/webp" />
<img src="https://ik.imagekit.io/jlo64/post1/nintendo3ds-white-back.jpg?tr=w-480" alt="An aqua-blue Nintendo 3DS with a stylus on a white background" class="blog_image" title="An aqua-blue Nintendo 3DS with a stylus on a white background" />
<figcaption style="text-align:center">My childhood in a nutshell.</figcaption>
</picture>