This is a valid RSS feed.
This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.
<p><a href="http://cdn.scooterlabs.com/wp/wp-content/uploads/tableau-workboo ...
line 51, column 0: (14 occurrences) [help]
<p><a href="http://cdn.scooterlabs.com/wp/wp-content/uploads/tableau-workboo ...
line 51, column 0: (14 occurrences) [help]
<p><a href="http://cdn.scooterlabs.com/wp/wp-content/uploads/tableau-workboo ...
line 105, column 0: (11 occurrences) [help]
<p><img loading="lazy" decoding="async" class="aligncenter size-large wp-ima ...
line 112, column 0: (6 occurrences) [help]
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;" ...
<p><iframe loading="lazy" width="640" height="400" src="https://www.loom.com ...
<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
>
<channel>
<title>Brian Cantoni</title>
<atom:link href="http://www.cantoni.org/feed" rel="self" type="application/rss+xml" />
<link>http://www.cantoni.org/</link>
<description>Software engineering leader and occasional side project hacker</description>
<lastBuildDate>Tue, 11 Mar 2025 15:53:39 +0000</lastBuildDate>
<language>en-US</language>
<sy:updatePeriod>
hourly </sy:updatePeriod>
<sy:updateFrequency>
1 </sy:updateFrequency>
<generator>https://wordpress.org/?v=6.7.1</generator>
<item>
<title>Tableau Workbook Thumbnail Viewer by Claude</title>
<link>http://www.cantoni.org/2025/03/11/tableau-workbook-thumbnail-viewer-by-claude</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Tue, 11 Mar 2025 15:52:59 +0000</pubDate>
<category><![CDATA[AI]]></category>
<category><![CDATA[Tableau]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1283</guid>
<description><![CDATA[Claude wrote for me a simple tool for viewing and optionally removing thumbnails from a Tableau workbook file. I’m calling it my Aha! moment for AI-assisted development :) I’ve been following along with Simon Willison’s blog and was really intrigued with Everything I built with Claude Artifacts this week: I’m a huge fan of Claude’s Artifacts feature, which lets you prompt Claude to create an interactive Single Page App (using HTML, CSS and JavaScript) and then view the result directly in the Claude interface, iterating on it further with the bot and then, if you like, copying out the resulting…]]></description>
<content:encoded><![CDATA[<div>
<div>Claude wrote for me a simple tool for viewing and optionally removing thumbnails from a Tableau workbook file. I’m calling it my Aha! moment for AI-assisted development :)</div>
<div></div>
<div>I’ve been following along with Simon Willison’s blog and was really intrigued with <a href="https://simonwillison.net/2024/Oct/21/claude-artifacts/">Everything I built with Claude Artifacts this week</a>:</div>
<blockquote>
<div>I’m a huge fan of Claude’s Artifacts feature, which lets you prompt Claude to create an interactive Single Page App (using HTML, CSS and JavaScript) and then view the result directly in the Claude interface, iterating on it further with the bot and then, if you like, copying out the resulting code.</div>
</blockquote>
<div>My first idea was something I’d recently been looking into: Tableau workbook thumbnails. Tableau workbooks are saved in .TWB or .TWBX format. Both of these are actually XML files and the difference is the .TWB contains just the workbook while .TWBX also includes the data. Thumbnail images are automatically saved in a <thumbnails> element that includes the Base64-encoded PNG file:</div>
<pre><thumbnails>
<thumbnail height='384' name='Commission Model' width='384'>
iVBORw0KGgoAAAANSUhEUgAAAYAAAAGACAYAAACkx7W/AAAACXBIWXMAAA7DAAAOwwHHb6hk
AAAgAElEQVR4nOzdZ3wd1Z34/8/cXlWuepclW7Jk2bIt23LHvYFNDS0EAiQQ0hOSbPaf3Syb
3SS/bDbLkiUBTCcQOhhj3HBTb1bvvfderqRb5/9AjoyxwDYYO0Tn/UQv3Tlzzpkzc+c7c+bO
...
</thumbnail>
...
</thumbnails></pre>
<div>Thumbnails are used in places like the recently-opened list in Tableau Desktop:</div>
<p><a href="http://cdn.scooterlabs.com/wp/wp-content/uploads/tableau-workbook-thumbnails.png"><img fetchpriority="high" decoding="async" class="aligncenter size-large wp-image-1282" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/tableau-workbook-thumbnails-1024x329.png" alt="Tableau Desktop recently opened workbooks represented by thumbnail images" width="688" height="221" srcset="http://www.cantoni.org/wp/wp-content/uploads/tableau-workbook-thumbnails-1024x329.png 1024w, http://www.cantoni.org/wp/wp-content/uploads/tableau-workbook-thumbnails-300x96.png 300w, http://www.cantoni.org/wp/wp-content/uploads/tableau-workbook-thumbnails-768x247.png 768w, http://www.cantoni.org/wp/wp-content/uploads/tableau-workbook-thumbnails-1536x493.png 1536w, http://www.cantoni.org/wp/wp-content/uploads/tableau-workbook-thumbnails-1600x514.png 1600w, http://www.cantoni.org/wp/wp-content/uploads/tableau-workbook-thumbnails.png 1712w" sizes="(max-width: 688px) 100vw, 688px" /></a></p>
<div>Thumbnails are handy but could be a concern if you’re sharing a workbook with other people and you’ve used it for viewing sensitive data. In that case you might want to remove those thumbnails before sharing.</div>
<div></div>
<div>My instructions to Claude (copying / inspired by Simon’s examples) were as follows:</div>
</div>
<div>
<blockquote><p>Build an artifact – no react – that accepts XML in a textarea (either typed in or with an upload button). Below the textarea create a button called Go that inspects the XML, finds how many <thumbnail> elements are present, and reports that number below. The elements contain base64 encoded PNG images – after printing the number of thumbnail elements, for each one decode and display the image on the web page.</p></blockquote>
<p>After a few iterations including adding buttons for removing the thumbnails and downloading the modified XML file, it worked! (Insert Aha! moment here.) Everything worked fine <span style="font-size: 1rem;">in the Claude console except for the download button. (I think there is some limitation when running in the iframe within Claude, but downloading and running locally worked fine.)</span></p>
<div>Here’s an example of the result, loading a workbook with the Superstore dataset which had 9 thumbnails. The app let’s you remove those thumbnails and save the .TWB file again. Success!</div>
<p><a href="http://cdn.scooterlabs.com/wp/wp-content/uploads/tableau-thumbnail-viewer.png"><img decoding="async" class="aligncenter size-large wp-image-1281" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/tableau-thumbnail-viewer-1006x1024.png" alt="Tableau workbook thumbnail viewer created by Claude" width="688" height="700" srcset="http://www.cantoni.org/wp/wp-content/uploads/tableau-thumbnail-viewer-1006x1024.png 1006w, http://www.cantoni.org/wp/wp-content/uploads/tableau-thumbnail-viewer-295x300.png 295w, http://www.cantoni.org/wp/wp-content/uploads/tableau-thumbnail-viewer-768x782.png 768w, http://www.cantoni.org/wp/wp-content/uploads/tableau-thumbnail-viewer-1509x1536.png 1509w, http://www.cantoni.org/wp/wp-content/uploads/tableau-thumbnail-viewer-1600x1629.png 1600w, http://www.cantoni.org/wp/wp-content/uploads/tableau-thumbnail-viewer.png 1772w" sizes="(max-width: 688px) 100vw, 688px" /></a></p>
</div>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
<item>
<title>From Laptop to Cloud: Scaling YouTube Video Transcription with LLMs</title>
<link>http://www.cantoni.org/2025/02/03/laptop-to-cloud-scaling-transcription-with-llms</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Tue, 04 Feb 2025 02:38:07 +0000</pubDate>
<category><![CDATA[AI]]></category>
<category><![CDATA[Video]]></category>
<category><![CDATA[Web]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1248</guid>
<description><![CDATA[My experiments around Summarizing YouTube Videos with LLMs have been working well on my Mac laptop, but I’d really like to run it as a service on a regular schedule. Running the OpenAI Whisper transcription process locally requires more than 1GB that my favorite Digital Ocean droplets provide. Instead I’ve added an option to run it directly against the OpenAI Transcriptions AI (the official OpenAI Python library makes it very easy). To use the online API you’ll need an API key set up either as pay-as-you-go or with a ChatGPT Plus subscription (which is what I have). After I’ve run…]]></description>
<content:encoded><![CDATA[<p>My experiments around <a href="http://www.cantoni.org/2025/01/21/summarizing-youtube-videos-with-llms">Summarizing YouTube Videos with LLMs</a> have been working well on my Mac laptop, but I’d really like to run it as a service on a regular schedule. Running the <a href="https://github.com/openai/whisper">OpenAI Whisper</a> transcription process locally requires more than 1GB that my favorite Digital Ocean droplets provide. Instead I’ve added an option to run it directly against the <a href="https://platform.openai.com/docs/guides/speech-to-text">OpenAI Transcriptions AI</a> (the official <a href="https://github.com/openai/openai-python">OpenAI Python library</a> makes it very easy).</p>
<p>To use the online API you’ll need an API key set up either as pay-as-you-go or with a ChatGPT Plus subscription (which is what I have). After I’ve run this for a while I’ll be able to tell what the usage might cost and whether upgrading to a larger droplet size would make more sense.</p>
<p>In any case this is working fine and I have it running hourly in the cloud!</p>
<p>Sample email from a Network Chuck video:</p>
<p><a href="http://cdn.scooterlabs.com/wp/wp-content/uploads/traaack-email-sample-network-chuck.png"><img decoding="async" class="aligncenter size-large wp-image-1247" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/traaack-email-sample-network-chuck-190x1024.png" alt="Sample email generated by summarizing the conversation in a YouTube video" width="190" height="1024" srcset="http://www.cantoni.org/wp/wp-content/uploads/traaack-email-sample-network-chuck-190x1024.png 190w, http://www.cantoni.org/wp/wp-content/uploads/traaack-email-sample-network-chuck-768x4145.png 768w, http://www.cantoni.org/wp/wp-content/uploads/traaack-email-sample-network-chuck-285x1536.png 285w" sizes="(max-width: 190px) 100vw, 190px" /></a></p>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
<item>
<title>Summarizing YouTube Videos with LLMs</title>
<link>http://www.cantoni.org/2025/01/21/summarizing-youtube-videos-with-llms</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Tue, 21 Jan 2025 22:05:08 +0000</pubDate>
<category><![CDATA[AI]]></category>
<category><![CDATA[Video]]></category>
<category><![CDATA[Web]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1224</guid>
<description><![CDATA[Over the holiday break I was thinking about taking transcriptions of YouTube videos and running them through an LLM for summaries. My inspiration was the dust up around Honey coupon code browser extension. Most of the news pointed to MegaLag’s video Exposing the Honey Influencer Scam. It’s a 23 minute video which isn’t too bad, but I wondered whether a summary would help here? Python Solution I built a simple pipeline in Python that takes a list of YouTube channels and produces a summary email for each published video: YouTube channels have a standard RSS feed which makes this first…]]></description>
<content:encoded><![CDATA[<p><span style="font-weight: 400;">Over the holiday break I was thinking about taking transcriptions of YouTube videos and running them through an LLM for summaries. My inspiration was the dust up around Honey coupon code browser extension. Most of the news pointed to MegaLag’s video </span><a href="https://www.youtube.com/watch?v=vc4yL3YTwWk"><span style="font-weight: 400;">Exposing the Honey Influencer Scam</span></a><span style="font-weight: 400;">. It’s a 23 minute video which isn’t too bad, but I wondered whether a summary would help here?</span></p>
<p><b>Python Solution</b></p>
<p><img loading="lazy" decoding="async" class="aligncenter size-large wp-image-1227" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/traaack-flow-1024x92.png" alt="A flowchart showing a process from "YouTube Channel" to "RSS Feed," "Audio Download," "Whisper Transcript," "LLM Summarize," and finally "Email," with arrows indicating the progression between each step." width="688" height="62" srcset="http://www.cantoni.org/wp/wp-content/uploads/traaack-flow-1024x92.png 1024w, http://www.cantoni.org/wp/wp-content/uploads/traaack-flow-300x27.png 300w, http://www.cantoni.org/wp/wp-content/uploads/traaack-flow-768x69.png 768w, http://www.cantoni.org/wp/wp-content/uploads/traaack-flow-1536x139.png 1536w, http://www.cantoni.org/wp/wp-content/uploads/traaack-flow-1600x144.png 1600w, http://www.cantoni.org/wp/wp-content/uploads/traaack-flow.png 1673w" sizes="auto, (max-width: 688px) 100vw, 688px" /></p>
<p><span style="font-weight: 400;">I built a simple pipeline in Python that takes a list of YouTube channels and produces a summary email for each published video:</span></p>
<p><b>YouTube</b><span style="font-weight: 400;"> channels have a standard RSS feed which makes this first step very simple. From the video URL I’m using yt-dlp to download the “best” audio stream which comes down in WebM format. Each video has a range of different audio qualities you can download, but this seemed to work fine. I didn’t go back to see if “worst” audio produced worse transcriptions, but the download is so small it doesn’t really matter. However what </span><i><span style="font-weight: 400;">does</span></i><span style="font-weight: 400;"> matter is downloading from YouTube is painful and there’s a constant battle with the download tools out there. Since this is just for personal use, I’m using my own cookies and that seems to be pretty reliable. It would be tricky to build a real service like this unless there was a real YouTube API for getting this data.</span></p>
<p><span style="font-weight: 400;">For </span><b>transcription</b><span style="font-weight: 400;"> I’m using </span><a href="https://github.com/openai/whisper"><span style="font-weight: 400;">OpenAI Whisper</span></a><span style="font-weight: 400;"> running locally. It has 6 different model sizes with tradeoffs in speed and accuracy. Right now I’m using “turbo” which is pretty high on memory usage but gives good quality results. This is definitely the slow part of the pipeline; the time to transcript goes in hand with the video length.</span></p>
<p><span style="font-weight: 400;">I started to run this project on a </span><b>Digital Ocean</b><span style="font-weight: 400;"> droplet, but my usual cheap choice (1 GB memory, 1 GB disk) definitely did not have enough memory to run Whisper. I did some quick tests with the OpenAI </span><a href="https://platform.openai.com/docs/guides/speech-to-text"><span style="font-weight: 400;">Speech to text API</span></a><span style="font-weight: 400;"> which worked great, so I might switch to that. In the meantime, this project runs on my MacBook Air.</span></p>
<p><span style="font-weight: 400;">To </span><b>summarize</b><span style="font-weight: 400;"> the generated transcript text, I used my favorite </span><a href="https://llm.datasette.io/en/stable/"><span style="font-weight: 400;">LLM command line tool</span></a><span style="font-weight: 400;"> from the Datasette project and the GPT-4o mini model. These are the prompts I used:</span></p>
<ul>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">“summarize this transcript of a youtube video” → this one is very simple but you could also make it a bit richer by asking for pull quotes for example</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">“reformat this text to add punctuation and paragraph breaks where it makes sense; try to keep as much of the original text, while making it easier to read” → this helped make the full transcription text much easier to read while not changing the content too much</span></li>
</ul>
<p><span style="font-weight: 400;">Also this was the first time I used </span><b>Github Copilot</b><span style="font-weight: 400;"> chat and autocomplete for a project from the start. The autocomplete in particular was surprisingly good with its suggestions; I suspect because this type of Python code is pretty common and I wasn’t exactly breaking any new ground here, but I had multiple “that’s exactly what I was going to type!” moments. I had mixed results with chat; for example I asked for a simple example of sending email with Python and it gave me a very convoluted example that didn’t actually work. Luckily the </span><a href="https://docs.python.org/3/library/email.examples.html"><span style="font-weight: 400;">Python email module examples</span></a><span style="font-weight: 400;"> were all I needed.</span></p>
<p><b>Example</b></p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1226" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/honey-scam-thumbnail.jpg" alt="Thumbnail for the Honey Influencer Scam YouTube video" width="478" height="287" srcset="http://www.cantoni.org/wp/wp-content/uploads/honey-scam-thumbnail.jpg 478w, http://www.cantoni.org/wp/wp-content/uploads/honey-scam-thumbnail-300x180.jpg 300w" sizes="auto, (max-width: 478px) 100vw, 478px" /></p>
<p><span style="font-weight: 400;">Going back to the Honey Influencer Scam video, here’s a sample of what the summaries look like.</span></p>
<p><span style="font-weight: 400;">First, the simple “summarize this video” result:</span></p>
<blockquote><p><span style="font-weight: 400;">The video outlines an extensive investigation into Honey, a free browser extension owned by PayPal, that promises to automatically apply coupon codes at checkout to save consumers money. The narrator alleges that Honey not only exploits consumers but also engages in deceptive practices that defraud influencers and content creators out of their rightful affiliate commissions.</span></p>
<p><span style="font-weight: 400;">Key Points from the Investigation:</span></p>
<ol>
<li><span style="font-weight: 400;">Commission Theft: When consumers use Honey after clicking on an influencer’s affiliate link, Honey replaces the affiliate cookie with its own, claiming the commission for itself, even if it doesn’t find a working coupon. This practice undermines influencers who promote products, as Honey effectively steals their commissions.</span></li>
<li><span style="font-weight: 400;">Honey Gold (Cashback) Mechanism: Honey introduced a cashback feature (now called PayPal Rewards) that encourages users to click through Honey at checkout to earn rewards. This system further benefits Honey by allowing them to claim commissions instead of paying it to the referring influencer.</span></li>
<li><span style="font-weight: 400;">Deceptive Practices: Honey often only shows coupons that are approved by partnering stores, which allows those stores to control which discounts are promoted. This contradicts Honey’s claim of finding the best deals available, leading to no transparency for consumers who believe they are getting the best price.</span></li>
<li><span style="font-weight: 400;">Influencer Response: Over time, some influencers, notably Linus Tech Tips, recognized that Honey was undermining their affiliate links and eventually ended their partnerships with Honey. However, the narrator expresses disappointment that these influencers didn’t publicly address these issues sooner given their significant audience reach.</span></li>
<li><span style="font-weight: 400;">Misleading Marketing Claims: The video critiques Honey’s marketing strategy, highlighting exaggerated claims about its capabilities to find every coupon code on the internet. The Better Business Bureau even investigated Honey’s advertising but ceased after Honey discontinued claim practices for “business reasons.”</span></li>
<li><span style="font-weight: 400;">Consumer Impact: The investigation suggests that the practices of Honey could cost influencers, bloggers, and other small content creators millions in lost commissions while misleading consumers into thinking they are getting the best deals. The narrator emphasizes that this deceptive model would not be tolerated in a traditional retail environment.</span></li>
</ol>
<p><span style="font-weight: 400;">The video presents Honey as a largely predatory service that financially benefits at the expense of both influencers and consumers by exploiting the affiliate marketing system and manipulating coupon code promotions.</span></p></blockquote>
<p><span style="font-weight: 400;">Second, here’s a snippet of the reformatted original transcript which I was pretty impressed with:</span></p>
<blockquote><p><span style="font-weight: 400;">But now, you’ve probably heard about Honey, you know, the browser extension that saves you money. So, you have Honey installed? What’s Honey? Oh, no, no. </span></p>
<p><span style="font-weight: 400;">Honey? Honey is a free browser extension. Free browser extension. Free browser extension. But automatically applies coupon codes when you check out online. Free money, basically. Literally free money. It doesn’t make sense not to be using this. </span></p>
<p><span style="font-weight: 400;">So what’s the catch? </span></p>
<p><span style="font-weight: 400;">There is… okay, join Honey. Join Honey. Honey. Honey. Honey. Honey. Honey. </span></p>
<p><span style="font-weight: 400;">Yeah, I hate to break it to you, but your favorite influencers sold you a lie. Honey is a scam, and the majority of claims promoted by those influencers aren’t even remotely true. But it gets worse. Honey hasn’t just been scamming you, the consumer; they’ve also been stealing money from influencers, including the very ones they pay to promote their product. And I’m not just talking about a few bucks here. I believe the scam has likely cost content creators millions of dollars. </span></p>
<p><span style="font-weight: 400;">Sound crazy? Well, I didn’t believe it at first either. Until I experienced it myself, firsthand. In fact, I’m confident this might just be the biggest influencer scam of all time, which is insane considering Honey is owned and run by PayPal, who purchased this company for $4 billion. This three-part series is the result of a multi-year investigation where I believe I’ve uncovered signs of advertising fraud, affiliate fraud, the illegal collection of personal data, deception, lies, coercion, extortion… the list goes on. I’ve reviewed hundreds of documents, advertisements, sponsorships; I’ve reviewed emails between Honey and merchants, interviewed victims—believe me, this runs deep. </span></p>
<p><span style="font-weight: 400;">Now, I want to be clear: the views, allegations, and conclusions expressed in the series are my opinions, based on evidence I have gathered, which will be shared throughout. With that said, ladies and gentlemen, this is the Honey Trip. </span></p></blockquote>
<p><b>Future Ideas and Conclusion</b></p>
<p><span style="font-weight: 400;">Future ideas to explore:</span></p>
<ul>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Include a time-stamped transcript in the result (Whisper generates a file you could use for this)</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Explore Whisper models to see if a faster model can be just as accurate</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Switch from local to cloud Whisper model and try running everything from a small Digital Ocean droplet</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Play around with the LLM prompts more</span></li>
</ul>
<p><span style="font-weight: 400;">So does this meet my goal of making videos easier to understand without watching? I think so, especially for the videos which are mainly narrating as opposed to building or doing something. I’m running with a set of 6 YouTube channels I follow to see how it goes.</span></p>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
<item>
<title>Forced to Retire Weather by Text Service</title>
<link>http://www.cantoni.org/2020/11/19/retire-weather-by-text</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Fri, 20 Nov 2020 05:16:55 +0000</pubDate>
<category><![CDATA[Cloud]]></category>
<category><![CDATA[Mobile]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1210</guid>
<description><![CDATA[I finally had to turn off the public number for my free Weather by Text service which I’ve been running for a few years. I was fine with the minimal cost running this on Twilio, but over the last couple of months someone has been abusing the number presumably with some automated script. The challenge with Twilio SMS is there is no way to block any abusive incoming text messages. Even though the pricing is pretty cheap ($ 0.0075 per message), it adds up quickly because you’re charged for both the incoming and outgoing messages. In the end, it’s not…]]></description>
<content:encoded><![CDATA[<p>I finally had to turn off the public number for my <a href="http://scooterlabs.com/wx/">free Weather by Text service</a> which I’ve been running for a few years. I was fine with the minimal cost running this on Twilio, but over the last couple of months someone has been abusing the number presumably with some automated script. The challenge with Twilio SMS is there is <strong>no way to block any abusive incoming text messages</strong>. Even though the pricing is pretty cheap ($ 0.0075 per message), it adds up quickly because you’re charged for both the incoming and outgoing messages. In the end, it’s not worth running a free service where one user can drive hundreds of abusive messages each day with no recourse. <span id="more-1210"></span></p>
<p>Coincidentally it was one year ago today I <a href="http://www.cantoni.org/2019/11/19/weather-by-text-twilio-darksky">rewrote the whole service</a> using <a href="https://developer.here.com/">HERE</a> for geocoding and <a href="https://darksky.net/poweredby/">DarkSky</a> for weather forecasts. I still have the code up on GitHub (<a href="https://github.com/bcantoni/wxtext">bcantoni/wxtext</a>) for anyone interested in running it themselves or just seeing how I built it.</p>
<p><strong>Update:</strong> After turning the service off I did hear back from Twilio tech support who let me know there <em>is</em> a way to block incoming fraudulent traffic. That’s encouraging. In this case I already decommissioned the service, but good to know for the future.</p>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
<item>
<title>Top 40 Podcasts</title>
<link>http://www.cantoni.org/2020/05/25/top-40-podcasts</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Mon, 25 May 2020 22:44:23 +0000</pubDate>
<category><![CDATA[Podcasting]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1199</guid>
<description><![CDATA[Here in California we’ve entered our third month of sheltering in place and working from home. One positive is less time spent commuting, but that also means it’s been harder to keep up with my podcast subscriptions. Combine that with the fact that there are so many good podcasts out there and I’ve had to shorten my subscription list a little bit (and be pickier about which episodes to listen to). Here’s my current Top 40* list of the best podcasts covering Technology/Software, Startups/Business, Woodworking/Makers and Sports: Technology / Software .NET Rocks! link feed .NET Rocks! is an Internet Audio…]]></description>
<content:encoded><![CDATA[<p>Here in California we’ve entered our third month of sheltering in place and working from home. One positive is less time spent commuting, but that also means it’s been harder to keep up with my podcast subscriptions. Combine that with the fact that there are <em>so many</em> good podcasts out there and I’ve had to shorten my subscription list a little bit (and be pickier about which episodes to listen to).<span id="more-1199"></span></p>
<p><img loading="lazy" decoding="async" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/alphacolor-66JMudIjDTw-unsplash.jpg" alt="headphones" width="1000" height="667" class="aligncenter size-full wp-image-1197" srcset="http://www.cantoni.org/wp/wp-content/uploads/alphacolor-66JMudIjDTw-unsplash.jpg 1000w, http://www.cantoni.org/wp/wp-content/uploads/alphacolor-66JMudIjDTw-unsplash-300x200.jpg 300w, http://www.cantoni.org/wp/wp-content/uploads/alphacolor-66JMudIjDTw-unsplash-768x512.jpg 768w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></p>
<p>Here’s my current Top 40<sup>*</sup> list of the best podcasts covering Technology/Software, Startups/Business, Woodworking/Makers and Sports:</p>
<h2>Technology / Software</h2>
<p><strong>.NET Rocks!</strong> <a href="http://www.dotnetrocks.com">link</a> <a href="http://feeds.feedburner.com/netRocksFullMp3Downloads">feed</a> .NET Rocks! is an Internet Audio Talk Show for Microsoft .NET Developers.</p>
<p><strong>Agile for Humans</strong> <a href="https://agile.fireside.fm">link</a> <a href="https://feeds.fireside.fm/agile/rss">feed</a> Agile for Human with Ryan Ripley is a weekly podcast dedicated to the individuals and interactions that make agile work. Our goal is to help you create safe and collaborative working environments where people are empowered to do their best work.</p>
<p><strong>Arrested DevOps</strong> <a href="https://www.arresteddevops.com">link</a> <a href="https://www.arresteddevops.com/episode/index.xml">feed</a> Arrested DevOps is the podcast that helps you achieve understanding, develop good practices, and operate your team and organization for maximum DevOps awesomeness.</p>
<p><strong>The Changelog</strong> <a href="https://changelog.com/podcast">link</a> <a href="https://changelog.com/podcast/feed">feed</a> Conversations with the hackers, leaders, and innovators of software development. Hosts Adam Stacoviak and Jerod Santo face their imposter syndrome so you don’t have to. Expect in-depth interviews with the best and brightest in software engineering, open source, and leadership. This is a polyglot podcast. All programming languages, platforms, and communities are welcome. Open source moves fast. Keep up.</p>
<p><strong>Code Story</strong> <a href="https://codestory.co/">link</a> <a href="https://feeds.transistor.fm/code-story">feed</a> Their tech. Their products. Their stories. Hosted by Noah Labhart, this show is a window into the digital startup world. In their own words, tech veterans share what it feels like to create a world class product, how to recover from critical mistakes, and how to scale your solution to the masses.</p>
<p><strong>Command Line Heroes</strong> <a href="https://www.redhat.com/en/command-line-heroes">link</a> <a href="https://feeds.pacific-content.com/commandlineheroes">feed</a> Stories about the people transforming technology from the command line up.</p>
<p><strong>Full Stack Radio</strong> <a href="http://fullstackradio.com">link</a> <a href="https://rss.simplecast.com/podcasts/279/rss">feed</a> A podcast for developers interested in building great software products. Every episode, Adam Wathan is joined by a guest to talk about everything from product design and user experience to unit testing and system administration.</p>
<p><strong>Girl Geek X</strong> <a href="https://girlgeek.io/">link</a> <a href="https://feeds.buzzsprout.com/245027.rss">feed</a> For women in tech, navigating your career can be as challenging as it is rewarding. Now, after giving female tech leaders a platform for over 10 years at Girl Geek Dinners, we’re sharing the best insight from women in tech every 1st and 3rd Monday. Whether you’re new to the tech world or at the height of your career, the Girl Geek X podcast has tips for you.</p>
<p><strong>Hanselminutes with Scott Hanselman</strong> <a href="https://www.hanselminutes.com">link</a> <a href="https://feeds.simplecast.com/gvtxUiIf">feed</a> Hanselminutes is Fresh Air for Developers. A weekly commute-time podcast that promotes fresh technology and fresh voices. Talk and Tech for Developers, Life-long Learners, and Technologists.</p>
<p><strong>Import This</strong> <a href="http://soundcloud.com/import-this">link</a> <a href="https://feed.pippa.io/public/shows/5cb74ed2304ec1540dfbbadd">feed</a> A Python Podcast for Humans.</p>
<p><strong>Page it to the Limit</strong> <a href="https://www.pageittothelimit.com">link</a> <a href="https://www.pageittothelimit.com/episode/index.xml">feed</a> Page It to the Limit is a podcast that focuses on what it means to operate software in production. Hosted by the PagerDuty Community Team, we cover the leading practices used in the software industry to improve both system reliability and the lives of the people responsible for supporting it.</p>
<p><strong>Planet Performance Podcast</strong> <a href="https://podcast.perfplanet.com">link</a> <a href="http://podcast.perfplanet.com/feed.xml">feed</a> Interviews with Web Performance enthusiasts</p>
<p><strong>Programming Leadership</strong> <a href="https://programmingleadership.podbean.com">link</a> <a href="https://feed.podbean.com/programmingleadership/feed.xml">feed</a> A podcast to help great coders become skilled leaders, and build happy, high-performing software teams.</p>
<p><strong>Real Talk JavaScript</strong> <a href="http://www.realtalkjs.com">link</a> <a href="https://feeds.simplecast.com/tOjNXec5">feed</a> Dive into JavaScript and Web development stories with hosts John Papa, Ward Bell, and Dan Wahlin.</p>
<p><strong>Screaming in the Cloud</strong> <a href="https://screaminginthecloud.com">link</a> <a href="https://feeds.transistor.fm/screaming-in-the-cloud">feed</a> Screaming in the Cloud with Corey Quinn features conversations with domain experts in the world of Cloud Computing. Topics discussed include AWS, GCP, Azure, Oracle Cloud, and the “why” behind how businesses are coming to think about the Cloud.</p>
<p><strong>Software Engineering Unlocked</strong> <a href="https://www.software-engineering-unlocked.com">link</a> <a href="https://feeds.simplecast.com/K1_mv0CJ">feed</a> In this show, I open you the doors to companies and thought leaders around the world. With my guests, I discuss software engineering best practices and pitfalls, and how they strive to build software people love.</p>
<p><strong>The Stack Overflow Podcast</strong> <a href="https://stackoverflow.blog/podcast/">link</a> <a href="https://feeds.simplecast.com/XA_851k3">feed</a> The Stack Overflow podcast is a weekly conversation about working in software development, learning to code, and the art and culture of computer programming. Hosted by Sara Chipps, Paul Ford, and Ben Popper, the series will feature questions from our community, interviews with fascinating guests, and hot takes on what’s happening in tech.</p>
<p><strong>Talk Python To Me</strong> <a href="https://talkpython.fm/">link</a> <a href="https://talkpython.fm/episodes/rss">feed</a> Talk Python to Me is a weekly podcast hosted by Michael Kennedy. The show covers a wide array of Python topics as well as many related topics. Our goal is to bring you the human story behind the Python packages and frameworks you know and love.</p>
<p><strong>Track Changes</strong> <a href="https://postlight.com/trackchanges/podcast">link</a> <a href="http://trackchanges.libsyn.com/rss">feed</a> What happens when software eats the world? Industry veterans Paul Ford and Rich Ziade chat with their friends about technology, design, and business from a distinctly East Coast point of view.</p>
<h2>Startups / Business</h2>
<p><strong>Bootstrapped Web</strong> <a href="http://bootstrappedweb.com/">link</a> <a href="http://bootstrappedweb.com/feed/podcast">feed</a> Bootstrapped Web is for entrepreneurs bootstrapping their startups, who believe that the best way to get to where we’re going is to learn by doing. Conversations, case studies, and interviews with entrepreneurs who are building profitable businesses online. Let’s do this.</p>
<p><strong>Bright & Early</strong> <a href="https://brianrhea.com">link</a> <a href="https://feeds.transistor.fm/bright-early">feed</a> A podcast for people building early-stage startups. Join me each week as I talk to entrepreneurs, product people, designers, and marketing pros about their experiences during the early days of their startup.</p>
<p><strong>Build Your SaaS – bootstrap in 2020</strong> <a href="https://saas.transistor.fm">link</a> <a href="https://feeds.transistor.fm/build-your-saas">feed</a> Can you bootstrap a profitable startup in 2020? Thousands of entrepreneurs, developers, designers, and product people have tried to launch their own web apps. But with so many venture-backed startups now, is it still possible? Follow Jon and Justin as they build their podcasting SaaS, Transistor.fm.</p>
<p><strong>The Important Thing</strong> <a href="https://randsinrepose.com/archives/category/the-important-thing/">link</a> <a href="http://rands.libsyn.com/feed">feed</a> The Important Thing with Michael (“Rands”) Lopp and Lyle Troxell. Let’s spend a few minutes of your life listening and learning about an Important Thing.</p>
<p><strong>Rogue Startups</strong> <a href="https://roguestartups.com/">link</a> <a href="https://roguestartups.com/feed/podcast">feed</a> The Rogue Startups podcast features two bootstrapped startup founders as they grow their businesses. We feature experts in the fields of sales, marketing, and product development to hear how they’re growth hacking their productized services, WordPress plugins, and SaaS products.</p>
<p><strong>Slow & Steady</strong> <a href="https://www.slowandsteadypodcast.com/">link</a> <a href="https://feeds.transistor.fm/slow-steady">feed</a> Join us as we share what it’s like to build and launch a bootstrapped startup while working for yourself full-time. Benedikt is working on Userlist with two other co-founders and Brian is running solo on a product to combat loneliness on remote teams.</p>
<p><strong>Smart Passive Income</strong> <a href="https://www.smartpassiveincome.com">link</a> <a href="http://feeds.feedburner.com/spipodcast">feed</a> Pat Flynn from The Smart Passive Income Blog reveals all of his online business and blogging strategies, income sources and killer marketing tips and tricks so you can be ahead of the curve with your online business or blog.</p>
<p><strong>Rework</strong> <a href="https://rework.fm">link</a> <a href="https://feeds.transistor.fm/rework">feed</a> A podcast by Basecamp about the better way to work and run your business. We bring you stories and unconventional wisdom from Basecamp’s co-founders and other business owners.</p>
<p><strong>Startups For the Rest of Us</strong> <a href="https://www.startupsfortherestofus.com/">link</a> <a href="https://feeds.feedblitz.com/startupsfortherestofus&x=1">feed</a> The longest running (and most popular) podcast for non-venture track startups, this show follow the stories of founders as they start, acquire, and grow SaaS companies.</p>
<h2>Woodworking / Makers</h2>
<p><strong>Clearstory</strong> <a href="http://www.thisoldhouse.com">link</a> <a href="https://feeds.megaphone.fm/clearstory">feed</a> From This Old House, Clearstory is a window that sheds light on the surprising stories behind our homes. Host Kevin O’Connor digs into the systems, structures and materials in our homes from unexpected angles. You’ll hear from Richard Trethewey, Tom Silva, Jeff Sweenor and the This Old House experts, as well as industry leaders, historians, and builders.</p>
<p><strong>Essential Craftsman</strong> <a href="https://essentialcraftsman.podbean.com">link</a> <a href="https://feed.podbean.com/essentialcraftsman/feed.xml">feed</a> In depth discussion of Essential Craftsman videos, related topics, spec house series, and more.</p>
<p><strong>Made for Profit</strong> <a href="https://madeforprofit.com">link</a> <a href="https://madeforprofit.com/feed/podcast/">feed</a> Brad Rodriguez & John Malecki are talking business in the shop and helping you monetize as a Maker.</p>
<p><strong>The Make or Break Show</strong> <a href="http://www.makeorbreakshop.com">link</a> <a href="https://feeds.transistor.fm/the-make-or-break-show">feed</a> The Make or Break Podcast is a weekly audio and video series that features amazing makers across the world. We dive into the greatest things they make as well as lessons learned from the things they break! Featuring woodworking, metalworking, electronics, 3d printing and more!</p>
<p><strong>Makers Weekly</strong> <a href="https://redcircle.com/shows/makers-weekly">link</a> <a href="https://api.podcache.net/shows/3ea4fbd6-b930-449a-9af0-8319d2feaa5a/feed">feed</a> We showcase recently launched products and creative projects by today’s modern makers. We explore the problems they’re solving, the tech they’re using, and tactics they’ve deployed to get to market successfully.</p>
<p><strong>Making It</strong> <a href="http://makingitpodcast.com/">link</a> <a href="http://makingitpodcast.libsyn.com/rss">feed</a> Making It is a weekly audio podcast hosted by Jimmy Diresta, Bob Clagett and David Picciuto. Three different makers with different backgrounds talking about creativity, design and making things with your bare hands.</p>
<p><strong>The Modern Maker Podcast</strong> <a href="https://www.stitcher.com/podcast/mike-montgomery-ben-uyeda-chris-salomone/the-modern-maker-podcast">link</a> <a href="https://feeds.megaphone.fm/modernmaker">feed</a> The Modern Maker Podcast is a weekly podcast about making things by hand. From wood, to concrete, to leather, our hosts Ben Uyeda, Chris Salomone, and Mike Montgomery chat about what it’s like to be a “Maker” in it’s current state.</p>
<h2>Sports</h2>
<p><strong>Danica Patrick Pretty Intense</strong> <a href="http://www.danicapatrick.com">link</a> <a href="https://feeds.simplecast.com/5LExlydD">feed</a> I’m Danica Patrick and I’m Pretty Intense! I believe that each and every one of us has the power within ourselves to create the life that we really want. And I want to inspire you to go conquer your dreams, both professionally and personally.</p>
<p><strong>NASCAR on NBC</strong> <a href="https://art19.com/shows/nascar-on-nbc-podcast">link</a> <a href="https://rss.art19.com/nascar-on-nbc-podcast">feed</a> Discussing the latest NASCAR news, including a weekly recap of races, events and a look ahead to what’s next in the sport. Guests include NBC Sports talent such as Jeff Burton, Steve Letarte and Kyle Petty.</p>
<p><strong>Sports Illustrated Media</strong> <a href="https://www.si.com/podcasts">link</a> <a href="http://feeds.feedburner.com/si-media">feed</a> Welcome to the Sports Illustrated Media Podcast with Jimmy Traina. This podcast, which will be published weekly, will focus on all things sports media via interviews and roundtable discussions. Occasionally, an athlete or celebrity will drop by for a chat as well.</p>
<p><strong>Sports Media with Richard Deitsch</strong> <a href="http://shows.cadence13.com/podcast/sports-media-with-richard-deitsch">link</a> <a href="http://feeds.feedburner.com/media-deitsch">feed</a> The Sports Media Podcast with Richard Deitsch is a weekly show that features interviews with members of the sports media about their work, as well as roundtables with sports media reporters about television, digital, audio/radio, print, and other forms of media.</p>
<p><sup>*</sup>Technically there are 41 here, but 40 was a nice round number…</p>
<p>Photo by <a href="https://unsplash.com/photos/66JMudIjDTw">Alphacolor on Unsplash</a></p>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
<item>
<title>WordPress Release Candidate Builds in Docker</title>
<link>http://www.cantoni.org/2020/03/05/wordpress-release-candidate-builds-docker</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Fri, 06 Mar 2020 03:54:16 +0000</pubDate>
<category><![CDATA[Web]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1116</guid>
<description><![CDATA[The first WordPress 5.4 release candidate was just published this week. The official WordPress Docker images are only published for release builds, so you can’t test any RC builds from there (for example on the Tags tab you won’t find 5.4-RC1 anywhere). However, it’s pretty straightforward to build the RC build yourself locally following these steps. Build Docker Image Locally The first step is to make a local clone of docker-library/wordpress (the official Docker image source tree for WordPress). Next we need to figure out what the SHA1 checksum is for the release candidate we’re going to use: Visit the…]]></description>
<content:encoded><![CDATA[<p>The first <a href="https://wordpress.org/news/2020/03/wordpress-5-4-release-candidate/">WordPress 5.4 release candidate</a> was just published this week. The <a href="https://hub.docker.com/_/wordpress/">official WordPress Docker images</a> are only published for release builds, so you can’t test any RC builds from there (for example on the Tags tab you won’t find <code>5.4-RC1</code> anywhere). However, it’s pretty straightforward to build the RC build yourself locally following these steps.<span id="more-1116"></span></p>
<h2>Build Docker Image Locally</h2>
<p>The first step is to make a local clone of <a href="https://github.com/docker-library/wordpress">docker-library/wordpress</a> (the official Docker image source tree for WordPress).</p>
<p>Next we need to figure out what the SHA1 checksum is for the release candidate we’re going to use:</p>
<ol>
<li>Visit the <a href="https://wordpress.org/download/releases/">Releases</a> page to understand the download link format</li>
<li>Find and copy the URL for one of the <code>sha1</code> files for the <code>tar.gz</code> download (in this case the latest is <a href="https://wordpress.org/wordpress-5.3.2.tar.gz.sha1">https://wordpress.org/wordpress-5.3.2.tar.gz.sha1</a>)</li>
<li>Substitute in the RC version and view the link to copy the SHA1 value (in this case we have <a href="https://wordpress.org/wordpress-5.4-RC1.tar.gz.sha1">https://wordpress.org/wordpress-5.4-RC1.tar.gz.sha1</a>) which returns <code>7cd079f329b1e9cc1c8148543081ae38301530e3</code></li>
</ol>
<p>Now you can edit the appropriate Dockerfile to refer to the RC release. The WordPress Docker tree currently has 3 different PHP versions and 4 different package types for a total of 12 options. In my case I’m using PHP 7.3 and Apache, so I’ll edit the file <code>php7.3/apache/Dockerfile</code>. Towards the bottom of that file you’ll see environment variables for WORDPRESS_VERSION and WORDPRESS_SHA1. Both of these need to be updated using the value from above:</p>
<pre><code>ENV WORDPRESS_VERSION 5.4-RC1
ENV WORDPRESS_SHA1 7cd079f329b1e9cc1c8148543081ae38301530e3
</code></pre>
<p>Now we can build the specific Docker image locally and tag it. Again using my example of PHP 7.3 + Apache, the build command will be:</p>
<pre><code>docker build ./php7.3/apache/ -t wordpress:5.4-RC1-php7.3-apache
</code></pre>
<p>On my old MacBook Pro this takes about 4 minutes. Assuming the build ran correctly, <code>docker images wordpress</code> should show the result:</p>
<pre><code>REPOSITORY TAG IMAGE ID CREATED SIZE
wordpress 5.4-RC1-php7.3-apache ca70b87fabb4 14 seconds ago 548MB
wordpress 5.3.2-php7.3-apache a9f43b7c47db 2 months ago 539MB
</code></pre>
<h2>Docker Compose with MySQL Database</h2>
<p>Finally, we can refer to that local RC1 image using Docker compose. Follow the instructions in <a href="https://docs.docker.com/compose/wordpress/">Compose and WordPress Quickstart</a> but don’t build the project just yet.</p>
<p>In the <code>docker-compose.yml</code> file, change the WordPress image line from <code>image: wordpress:latest</code> to <code>image: wordpress:5.4-RC1-php7.3-apache</code>.</p>
<p>Now you can continue the instructions by building the project <code>docker-compose up -d</code>. In a few minutes you should now have a running WordPress release candidate!</p>
<h2>Notes</h2>
<ul>
<li>I’ve used the same technique with my <a href="http://www.cantoni.org/2019/10/25/wordpress-github-docker">new WordPress workflow</a> and it worked really well. Also 5.4-RC1 didn’t exhibit any problems, but that’s what I expected considering my use case and plugin collection is pretty simple.</li>
<li>Subscribe to <a href="https://wordpress.org/news/">WordPress News</a> if you’d like to be notified of all release candidate and normal updates. For normal releases, it can take a couple days for the official Docker images to be updated.</li>
</ul>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
<item>
<title>How to Host a Coming Soon Landing Page on AWS S3</title>
<link>http://www.cantoni.org/2020/02/08/host-coming-soon-page-on-aws-s3</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Sat, 08 Feb 2020 23:26:58 +0000</pubDate>
<category><![CDATA[Other]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1106</guid>
<description><![CDATA[I recently launched a coming soon landing page for Engineering Tourist – a side project I’ve had in mind for a while. The goal is to highlight and discover engineering or technical tourist sites depending on your location. For example if you were in Tucson Arizona, you might discover the Pima Air & Space Museum which is really fantastic. Putting together this landing page was pretty simple (after all, it’s just a single static page), but involved learning and wiring up a bunch of services. Also, every service here is at the free or nearly-free level, so that keeps the…]]></description>
<content:encoded><![CDATA[<p>I recently launched a coming soon landing page for <a href="https://engineeringtourist.com/">Engineering Tourist</a> – a side project I’ve had in mind for a while. The goal is to highlight and discover engineering or technical tourist sites depending on your location. For example if you were in Tucson Arizona, you might discover the <a href="https://pimaair.org/">Pima Air & Space Museum</a> which is really fantastic. Putting together this landing page was pretty simple (after all, it’s just a single static page), but involved learning and wiring up a bunch of services. Also, every service here is at the free or nearly-free level, so that keeps the costs minimal as well.<span id="more-1106"></span></p>
<p><a href="https://engineeringtourist.com/"><img loading="lazy" decoding="async" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/EngineeringTouristWebsite.png" alt="Screenshot of engineering tourist website" width="953" height="697" class="aligncenter size-full wp-image-1105" srcset="http://www.cantoni.org/wp/wp-content/uploads/EngineeringTouristWebsite.png 953w, http://www.cantoni.org/wp/wp-content/uploads/EngineeringTouristWebsite-300x219.png 300w, http://www.cantoni.org/wp/wp-content/uploads/EngineeringTouristWebsite-768x562.png 768w" sizes="auto, (max-width: 953px) 100vw, 953px" /></a></p>
<h2>Amazon Web Services</h2>
<p>The core of this solution is all built on AWS. This site is the example I used while following along with <a href="http://www.cantoni.org/2019/11/15/review-learn-aws-by-using-it">Learn AWS By Using It</a>. It was really helpful to have an actual live project rather than just an “example.com” sort of thing.</p>
<p>Deploying a static website on AWS required learning and using several different services:</p>
<ul>
<li>S3 for static files (the easy part)</li>
<li>CloudFront CDN for better performance around the world</li>
<li>Route 53 for DNS management</li>
<li>Certificate Manager for domain registration and SSL certificate</li>
<li>Simple Email Service for sending messages from EmailOctopus (more below)</li>
</ul>
<h2>Web Site Content</h2>
<p>The goal here was to create a single “coming soon” landing page to collect email addresses, so I started with the <a href="https://html5up.net/eventually">Eventually</a> from HTML5 UP. I wanted to set up a more automated build process for the CSS and JavaScript, so I learned and used <a href="https://gulpjs.com/">gulp</a> for the first time. Among other things it minimizes the image sizes automatically and compresses/combines the status CSS/JS files.</p>
<p>For a starting set of background images, I went through my own collection and picked <a href="https://walkway.org/">Walkway Over The Hudson</a>, <a href="https://www.indianapolismotorspeedway.com/">Indianapolis Motor Speedway</a>, <a href="https://pimaair.org/">Pima Air & Space</a>, <a href="https://www.thehenryford.org/">The Henry Ford</a>, and <a href="https://www.midway.org/">USS Midway Aircraft Carrier</a>.</p>
<p>For deployment, I have a script that uses the <a href="https://aws.amazon.com/cli/">AWS CLI</a> to publish everything to S3. With the CLI I can also control the cache time for all the static files: the main index.html is set for 1 hour and everything else is set for 7 days (but could be longer actually). When I start making changes more frequently here it’ll make sense to automate this deployment with each push to GitHub, but for now running this script works fine.</p>
<h2>StaticKit</h2>
<p>The <a href="https://statickit.com/">StaticKit</a> service provides forms and server-side functionality for static websites. In my case I’m using a simple contact form to gather email addresses which are stored and downloadable from the StaticKit site. Adding and deploying this signup form to my static site was really easy and the free plan should be good enough for now.</p>
<h2>Zapier</h2>
<p><a href="https://zapier.com/">Zapier</a> is used to wire up the new data captured into StaticKit. Thanks to the <a href="https://zapier.com/apps/statickit/integrations">Zapier StaticKit integration</a>, it was easy to create two Zaps:</p>
<ul>
<li>New form submission → Add subscriber in EmailOctopus</li>
<li>New form submission → Send SMS via Twilio to my mobile phone</li>
</ul>
<p>Since I’m just on the free plan with Zapier, this had to be two separate Zaps. For those on any of the paid plans, you can implement this with a simpler “multi step Zap”. Receiving a text message with each new subscriber is just for fun and I’d probably turn that off for anything that became popular.</p>
<h2>EmailOctopus</h2>
<p>I’m using MailChimp for some of my other projects but their free tier has become confusing and more restrictive over time. <a href="https://emailoctopus.com/">EmailOctopus</a> has a generous free tier so I’m giving it a try with this project.</p>
<p>EmailOctopus uses <a href="https://aws.amazon.com/ses/">Amazon SES</a> to send emails, so you’ll need to have an AWS account. The setup process has several steps (including giving EmailOctopus permission to send via your account and setting up SES to send from your domain), but the documentation provided walks you through everything and I didn’t have any problems.</p>
<h2>Conclusion</h2>
<p>Now that I’ve written it all down, that’s a long list of services just to launch a simple single-page website and collect email addresses! If your goal is to just quickly put together a coming soon page like this, it would probably be faster to use a paid service or a WordPress site + plugin. In my case I guess “the journey is the reward”, i.e. a chance to learn a bit about all these services.</p>
<p>The other takeaway is how easy it is to assemble something out of all the parts. Even though there are a lot of moving pieces here, most of it was just “wiring up” services. The only code I wrote was a bit of JavaScript.</p>
<p>Finally, if you’re interested in <a href="https://engineeringtourist.com/">engineering tourism</a> at all, please sign up to keep in touch!</p>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
<item>
<title>Barcode Scanning Video Games Collection</title>
<link>http://www.cantoni.org/2020/01/23/barcode-scanning-video-games-collection</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Thu, 23 Jan 2020 20:49:55 +0000</pubDate>
<category><![CDATA[Fun]]></category>
<category><![CDATA[Hardware]]></category>
<category><![CDATA[Tools]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1096</guid>
<description><![CDATA[As part of my ongoing effort to clean up all my old computer hardware, I finally organized all my video games for donation, and used a cheap barcode scanner to take inventory. We’re keeping GameCube and Wii, but donating XBox, XBox 360, PS/2 and PC games. This seemed like a good time to try barcode scanning to make a full list. On Amazon I bought a cheap wired USB barcode scanner (affiliate link, currently $14) and then created some Python scripts to find the game title from the barcode value. The scripts dump these into a CSV file for importing…]]></description>
<content:encoded><![CDATA[<p>As part of my ongoing effort to <a href="http://www.cantoni.org/2019/07/30/how-to-tidy-up-your-digital-life">clean up</a> all my old computer hardware, I finally organized all my video games for donation, and used a cheap barcode scanner to take inventory.<span id="more-1096"></span></p>
<p>We’re keeping GameCube and Wii, but donating XBox, XBox 360, PS/2 and PC games. This seemed like a good time to try barcode scanning to make a full list. On Amazon I bought a cheap <a href="https://amzn.to/30Qe9ER">wired USB barcode scanner</a> (affiliate link, currently $14) and then created some Python scripts to find the game title from the barcode value. The scripts dump these into a CSV file for importing into Excel or Google Sheets.</p>
<p><img loading="lazy" decoding="async" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/BarcodeScanGames.jpg" alt="Barcode scanning old video games with Mac laptop" width="1000" height="760" class="aligncenter size-full wp-image-1095" srcset="http://www.cantoni.org/wp/wp-content/uploads/BarcodeScanGames.jpg 1000w, http://www.cantoni.org/wp/wp-content/uploads/BarcodeScanGames-300x228.jpg 300w, http://www.cantoni.org/wp/wp-content/uploads/BarcodeScanGames-768x584.jpg 768w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></p>
<p>Here’s what the result looks like in action, in a short <a href="https://www.loom.com/share/900eebf21bc64a6493883596385224da">Loom video</a>:</p>
<p><iframe loading="lazy" width="640" height="400" src="https://www.loom.com/embed/900eebf21bc64a6493883596385224da" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></p>
<p>The code ended up being pretty straightforward but I ended up using two different sources to convert barcode numbers into game titles. (UPC barcode APIs is kind of a messy world which I didn’t quite understand, especially for cheap/free.) I’m using <a href="https://www.pricecharting.com">Price Charting</a> for all the console games and <a href="https://www.upcitemdb.com">upcitemdb.com</a> just for the PC games. The interface for reading barcode numbers from the scanner is really simple: whenever you scan something, it’s equivalent to the keyboard typing in: <code><barcode number> [Enter]</code>, so the code just treats it as any normal input.</p>
<p>I posted the scripts in a <a href="https://gist.github.com/bcantoni/a9a689b441330d83ab74ea859b76e06d">Github gist</a> for those that might be interested.</p>
<p>In the end I’ve got over 90 games (and consoles/controllers) for donation. The plan is to bring them up to <a href="https://themade.org/">The MADE</a> the next time I’m heading that way!</p>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
<item>
<title>Resurrecting a Dell Precision Workstation 410</title>
<link>http://www.cantoni.org/2020/01/21/resurrecting-dell-precision-workstation-410</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Wed, 22 Jan 2020 00:10:19 +0000</pubDate>
<category><![CDATA[Hardware]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1091</guid>
<description><![CDATA[I’m finally making some good progress sorting through all my old computer hardware for donation or recycling. My collection of old laptops, desktops and computer cables are finally out of my garage and donated to my local Goodwill. This mostly went quickly except for a brief nostalgic time spent with my old workhorse, a Dell Precision Workstation 410MT. The 410MT was first released in 1998. I was at Palm at the time and this was the standard “developer’s desktop” system we started buying. We cycled them through every 3-4 years, and I picked this one up from an internal surplus…]]></description>
<content:encoded><![CDATA[<p>I’m finally making some good progress sorting through all my <a href="http://www.cantoni.org/2019/07/30/how-to-tidy-up-your-digital-life">old computer hardware for donation or recycling</a>. My collection of old laptops, desktops and computer cables are finally out of my garage and donated to my local Goodwill.</p>
<p>This mostly went quickly except for a brief nostalgic time spent with my old workhorse, a Dell Precision Workstation 410MT.<span id="more-1091"></span></p>
<p><img loading="lazy" decoding="async" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/DellPrecision-960x1024.jpg" alt="front of Dell Precision Workstation case" width="688" height="734" class="aligncenter size-large wp-image-1087" srcset="http://www.cantoni.org/wp/wp-content/uploads/DellPrecision-960x1024.jpg 960w, http://www.cantoni.org/wp/wp-content/uploads/DellPrecision-281x300.jpg 281w, http://www.cantoni.org/wp/wp-content/uploads/DellPrecision-768x819.jpg 768w, http://www.cantoni.org/wp/wp-content/uploads/DellPrecision.jpg 1000w" sizes="auto, (max-width: 688px) 100vw, 688px" /></p>
<p>The 410MT was first released in 1998. I was at Palm at the time and this was the standard “developer’s desktop” system we started buying. We cycled them through every 3-4 years, and I picked this one up from an internal surplus sale/giveaway probably around 2004.</p>
<p>The stats were not too impressive by modern standards:</p>
<ul>
<li>Pentium II 400MHz (optionally with dual processors; mine just had a single)</li>
<li>256MB RAM (max was 1GB)</li>
<li>Windows NT 4.0</li>
</ul>
<p>On the plus side this was a big tower with tons of expansion slots and room for drives. A nice touch (I’m not sure whether all Dell enterprise products are like this) was everything in the chassis had easy release levers. Even the power supply could swing up out of the way and still remain cabled to the motherboard (no tools required).</p>
<p>At the time I picked this up from company surplus, I installed dual 150GB drives set to mirror each other, then installed Windows Server 2003. I used it for a few years as a home server, naming it Mufasa because the kids liked Lion King when they were younger. (I believe I also had laptops named Simba and Timon, but those have long since been recycled.) I don’t recall why exactly I stopped using this, but it was probably too loud and too big to be worth running just a simple file server.</p>
<p>This server had gathered quite a bit of dust in the garage, but it fired right up. I even remembered the admin password which was a small miracle. The event log confirmed the last boot was in February 2009, so this machine sat quietly for 11 years and still worked.</p>
<p><img loading="lazy" decoding="async" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/DellEventLog.jpg" alt="Event log showing last system boot was 11 years ago" width="750" height="313" class="aligncenter size-full wp-image-1086" srcset="http://www.cantoni.org/wp/wp-content/uploads/DellEventLog.jpg 750w, http://www.cantoni.org/wp/wp-content/uploads/DellEventLog-300x125.jpg 300w" sizes="auto, (max-width: 750px) 100vw, 750px" /></p>
<p>“Worked” should be in quotes because while the server did boot, it was woefully out of date. It was already up to Windows Server 2003 SP2, but the Windows Update Service would peg at 100% CPU but never seemed to make a connection. The browsers installed were IE 7.0 and Firefox 1.0, neither of which could be upgraded directly. I wasn’t able to find a working Firefox or Chrome browser but did finally find a downloadable IE8 which worked. One thing that makes this tricky is the “Windows Server browser enhanced security” which really limits the scope of websites you can visit from the server (for security reasons).</p>
<p>Once IE8 was installed and the system restarted, the Windows update service became functional again and over the course of the weekend many updates were downloaded and applied. Once everything was stable, I was able to copy out some of the files I wanted to make sure were backed up. Then I could wipe the drive (thanks <a href="https://www.ultimatebootcd.com/">Ultimate Boot CD</a>) and send it off to recycle!</p>
<p><img loading="lazy" decoding="async" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/HardwareDonation-1024x546.jpg" alt="used computers on their way to donation" width="688" height="367" class="aligncenter size-large wp-image-1090" srcset="http://www.cantoni.org/wp/wp-content/uploads/HardwareDonation-1024x546.jpg 1024w, http://www.cantoni.org/wp/wp-content/uploads/HardwareDonation-300x160.jpg 300w, http://www.cantoni.org/wp/wp-content/uploads/HardwareDonation-768x409.jpg 768w, http://www.cantoni.org/wp/wp-content/uploads/HardwareDonation.jpg 1100w" sizes="auto, (max-width: 688px) 100vw, 688px" /></p>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
<item>
<title>How to Convert Word DOC to DOCX Format</title>
<link>http://www.cantoni.org/2020/01/15/how-to-convert-word-doc-to-docx-format</link>
<dc:creator><![CDATA[Brian Cantoni]]></dc:creator>
<pubDate>Wed, 15 Jan 2020 21:12:41 +0000</pubDate>
<category><![CDATA[Tools]]></category>
<category><![CDATA[Web]]></category>
<guid isPermaLink="false">http://www.cantoni.org/?p=1081</guid>
<description><![CDATA[Newer versions of Microsoft Word (in particular, Office 365) will no longer open older .DOC files. If you want to convert these to the current supported .DOCX format (especially if you have a batch of files to convert), LibreOffice is a good option. LibreOffice is free open-source software and you’ll get the benefit of doing everything on your computer. There are a lot of online services which advertise converting these files, but for anything personal or confidential I prefer keeping everything local. Quick Background As part of my effort to tidy up my digital life, I’ve been cleaning off and…]]></description>
<content:encoded><![CDATA[<p>Newer versions of Microsoft Word (in particular, Office 365) will no longer open older .DOC files. If you want to convert these to the current supported .DOCX format (especially if you have a batch of files to convert), <a href="https://www.libreoffice.org/">LibreOffice</a> is a good option.</p>
<p>LibreOffice is free open-source software and you’ll get the benefit of doing everything on your computer. There are a lot of online services which advertise converting these files, but for anything personal or confidential I prefer keeping everything local.<span id="more-1081"></span></p>
<h2>Quick Background</h2>
<p>As part of my effort to <a href="http://www.cantoni.org/2019/07/30/how-to-tidy-up-your-digital-life">tidy up my digital life</a>, I’ve been cleaning off and recycling old computers and consolidating a bunch of backup hard drives and disks. Among other gems I found a bunch of old .DOC files and learned that modern versions of Microsoft Word could not open them at all.</p>
<p>I assume this is for security protection reasons, perhaps to block against macros and other live code which were possible in those older formats. Unfortunately this can lead to “format rot” where you have perfectly valid archived files which are no longer usable.</p>
<p>For example, using Word for Mac (Office 365 version), I get this block when I try to open old .DOC files:</p>
<p><img loading="lazy" decoding="async" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/Word365Mac.png" alt="Error dialog from Word on Mac" width="635" height="292" class="aligncenter size-full wp-image-1078" srcset="http://www.cantoni.org/wp/wp-content/uploads/Word365Mac.png 635w, http://www.cantoni.org/wp/wp-content/uploads/Word365Mac-300x138.png 300w" sizes="auto, (max-width: 635px) 100vw, 635px" /></p>
<p>The link points to this support article: <a href="https://support.office.com/en-us/article/error-filename-uses-a-file-type-that-is-blocked-from-opening-in-this-version-8afc36c0-67bc-43a9-a2f4-3f0b332fef24?ui=en-US&rs=en-US&ad=US">Error: [Filename] uses a file type that is blocked from opening in this version – Word for Mac</a>.</p>
<p>On Windows (also Office 365 subscription version), it will open these files but in protected mode (meaning, no edits are possible):</p>
<p><img loading="lazy" decoding="async" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/Word365Windows.png" alt="Warning dialog from Word on Mac" width="1000" height="92" class="aligncenter size-full wp-image-1079" srcset="http://www.cantoni.org/wp/wp-content/uploads/Word365Windows.png 1000w, http://www.cantoni.org/wp/wp-content/uploads/Word365Windows-300x28.png 300w, http://www.cantoni.org/wp/wp-content/uploads/Word365Windows-768x71.png 768w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></p>
<p>Luckily if you’re on Windows you can adjust the settings (Trust Center | File Block Settings) to enable older files which you trust to be opened:</p>
<p><img loading="lazy" decoding="async" src="http://cdn.scooterlabs.com/wp/wp-content/uploads/Word365WindowsTrustCenter.png" alt="Word trust center settings dialog" width="826" height="678" class="aligncenter size-full wp-image-1080" srcset="http://www.cantoni.org/wp/wp-content/uploads/Word365WindowsTrustCenter.png 826w, http://www.cantoni.org/wp/wp-content/uploads/Word365WindowsTrustCenter-300x246.png 300w, http://www.cantoni.org/wp/wp-content/uploads/Word365WindowsTrustCenter-768x630.png 768w" sizes="auto, (max-width: 826px) 100vw, 826px" /></p>
<p>Finally, if you do have an Office 365 online subscription, these older .DOC files <em>can</em> be viewed. If you want to edit online, it will offer to convert to the newest format for you. This looks like the easiest option if you just have an occasional file you need to convert.</p>
<h2>Installing LibreOffice</h2>
<p>For anything more than the occasional file, LibreOffice is a good option for converting multiple files quickly.</p>
<p>To install, follow the <a href="https://www.libreoffice.org/get-help/install-howto/">LibreOffice installation instructions</a>.</p>
<p>In my case on macOS I like to install things with Brew where possible, so my install step was simply:</p>
<pre><code>$ brew cask install libreoffice libreoffice-language-pack
</code></pre>
<p>Open the LibreOffice app one time to make sure everything was installed and configured correctly.</p>
<h2>Converting DOC to DOCX with LibreOffice</h2>
<p>With LibreOffice installed, you can convert files two different ways. The first way is to open the .DOC file and then “save as” in the .DOCX format. I experimented with this on a few files and it works fine.</p>
<p>If you have several files to convert, you can use the command line. The location will depend on which platform you’re using, but in my case (macOS), it looks like the following.</p>
<p>First to make sure you have the right location, and to see the online help, try the following:</p>
<pre><code>/Applications/LibreOffice.app/Contents/MacOS/soffice --help
</code></pre>
<p>In the help you’ll see the <code>--convert-to</code> and <code>--outdir</code> options which we’ll be using. A simple conversion of one file will look like this:</p>
<pre><code>/Applications/LibreOffice.app/Contents/MacOS/soffice --headless --convert-to docx FILE.DOC
</code></pre>
<p>Converting a directory full of files is possible as well:</p>
<pre><code>$ /Applications/LibreOffice.app/Contents/MacOS/soffice --headless --convert-to docx --outdir ~/Desktop/output ~/Desktop/convert/*.DOC
convert ~/Desktop/convert/BAZ.DOC -> ~/Desktop/output/BAZ.docx using filter : Office Open XML Text
convert ~/Desktop/convert/CATHY.DOC -> ~/Desktop/output/CATHY.docx using filter : Office Open XML Text
convert ~/Desktop/convert/FONTS.DOC -> /Users/brian/Desktop/output/FONTS.docx using filter : Office Open XML Text
convert ~/Desktop/convert/RESIGN.DOC -> ~/Desktop/output/RESIGN.docx using filter : Office Open XML Text
</code></pre>
<p>All of the DOCX files should now be fully working in Word. It’s possible that complicated documents may have some layout issues during conversion, but I think those should be relatively minor.</p>
<!-- Cantoni plugin -->
]]></content:encoded>
</item>
</channel>
</rss>
If you would like to create a banner that links to this page (i.e. this validation result), do the following:
Download the "valid RSS" banner.
Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)
Add this HTML to your page (change the image src
attribute if necessary):
If you would like to create a text link instead, here is the URL you can use:
http://www.feedvalidator.org/check.cgi?url=http%3A//www.cantoni.org/feed