<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tomas Gallucci</title>
    <description>The latest articles on DEV Community by Tomas Gallucci (@professortom).</description>
    <link>https://dev.to/professortom</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F141463%2F70250ff4-8841-4d27-822d-f18489296253.png</url>
      <title>DEV Community: Tomas Gallucci</title>
      <link>https://dev.to/professortom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/professortom"/>
    <language>en</language>
    <item>
      <title>From GET/POST to Full REST: My Recent PacketSender HTTP Verbs PR</title>
      <dc:creator>Tomas Gallucci</dc:creator>
      <pubDate>Wed, 24 Jun 2026 00:19:14 +0000</pubDate>
      <link>https://dev.to/professortom/from-getpost-to-full-rest-my-recent-packetsender-http-verbs-pr-481g</link>
      <guid>https://dev.to/professortom/from-getpost-to-full-rest-my-recent-packetsender-http-verbs-pr-481g</guid>
      <description>&lt;p&gt;&lt;a href="https://packetsender.com" rel="noopener noreferrer"&gt;PacketSender&lt;/a&gt; is an Open Source, low-level networking tool that, until a few days ago, only supported HTTP/S POST and GET.&lt;/p&gt;

&lt;p&gt;As I write these words, I'm waiting on final review and approval for adding PUT, PATCH and DELETE support.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I got Involved with this Work
&lt;/h2&gt;

&lt;p&gt;I’ve made previous contributions to PacketSender, some of which I'd like to explore in other posts.&lt;/p&gt;

&lt;p&gt;I've been out of professional work for a long time. COVID really screwed everything up and the whipsaw of fire everybody, hire as many people as you can, fire them again, replace them with AI has not been my friend.&lt;/p&gt;

&lt;p&gt;In the interim, I’ve been trying to keep my skills sharp.&lt;/p&gt;

&lt;p&gt;When I reached out to Dan Nagle, the author and maintainer, asking if there were any open areas where I could help, he pointed me to some client-funded work around expanding HTTP verb support (&lt;a href="https://github.com/dannagle/PacketSender/issues/340" rel="noopener noreferrer"&gt;PUT, PATCH and DELETE&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  What do we Program?
&lt;/h2&gt;

&lt;p&gt;Somewhere along the way, the way we talk about programming changed.&lt;/p&gt;

&lt;p&gt;When I first got into this field, the literature loved to say we were “programming the processor.” It painted this romantic image of directly commanding the silicon. &lt;/p&gt;

&lt;p&gt;Of course, this was after the industry evolved from machines that took up entire buildings, then shrank to rooms, corners of rooms. Mainframes and so-called minicomputers were on that path. Personal Computers or PCs had long since become ubiquitous when I got interested in computers, but they were still a long way from or more being in everyone's home. Now we carry them in our pockets.&lt;/p&gt;

&lt;p&gt;It rarely true that one programs the hardware these days. Web developers use JavaScript to program web browsers. Application development is programming operating systems and sometimes windowing systems.&lt;/p&gt;

&lt;p&gt;PacketSender is a C++ application that sits on top of Qt.&lt;/p&gt;

&lt;p&gt;From my perspective, I initially thought the work involved was going to be adding a few commands inside PaketSender to tell Qt how to handle the request. That turned out to be the case, but there was a moment or two of panic during this journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programming Qt
&lt;/h2&gt;

&lt;p&gt;As you can see &lt;a href="https://github.com/dannagle/PacketSender/issues/340#issuecomment-1780291153" rel="noopener noreferrer"&gt;from the comments&lt;/a&gt;, Dan knew that Qt supported both PUT and DELTE. PATCH was potentially dodgier. It turns out, all three are supported by Qt, but  not all three have direct support.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendpacket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isPUT&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendpacket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isPATCH&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sendCustomRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"PATCH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendpacket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isDELETE&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;deleteResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sendCustomRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"DELETE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/dannagle/PacketSender/pull/419/changes#diff-36a559429d24063c4335feee2f28494bc9ca558673695612994344ad06edf1da" rel="noopener noreferrer"&gt;direct Github PR diff link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from the code above, &lt;code&gt;PUT&lt;/code&gt; is directly supported. &lt;code&gt;DELETE&lt;/code&gt; has a funny name, but it works. But to get &lt;code&gt;PATCH&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; with data to work, we have to use &lt;code&gt;sendCustomRequest&lt;/code&gt;. And that's not terrible. Why these aren't directly supported in Qt6 is beyond me, but it isn't too onerous to get support working.&lt;/p&gt;

&lt;p&gt;But just because we can send the HTTP/S requests, that doesn't mean we're done. We have to get data from the user to send.&lt;/p&gt;

&lt;h2&gt;
  
  
  PacketSender is &lt;strong&gt;not&lt;/strong&gt; Postman
&lt;/h2&gt;

&lt;p&gt;As of this writing, PacketSender does not support custom HTTP headers. That feature &lt;em&gt;could&lt;/em&gt; be added.&lt;/p&gt;

&lt;p&gt;PacketSender is an Open Source project. Like all Open Source projects, time, &lt;a href="//github.com/dannagle/PacketSender/"&gt;talent&lt;/a&gt; and &lt;a href="https://packetsender.com/download" rel="noopener noreferrer"&gt;treasure&lt;/a&gt;) are always welcome.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;my personal opinion&lt;/strong&gt;, PacketSender shouldn't become the next Postman.&lt;/p&gt;

&lt;p&gt;PacketSender's core strength has always been as a &lt;strong&gt;lightweight, low-level networking tool&lt;/strong&gt;. It lets you send raw TCP and UDP packets with fine-grained control. HTTP support was added as a convenience layer on top of that foundation — not as the main focus.&lt;/p&gt;

&lt;p&gt;Postman is a specialized API testing tool with all the complexity that comes with it (headers, auth flows, collections, environments, etc.). Trying to turn PacketSender into a full-featured HTTP client would require significant work on both the backend logic &lt;em&gt;and&lt;/em&gt; the UI. Doing so would risk diluting what makes PacketSender valuable in the first place.&lt;/p&gt;

&lt;p&gt;I believe there's still a strong place for a simpler, more surgical tool focused on raw networking operations.&lt;/p&gt;

&lt;p&gt;I also think there is a market for less complicated Postman clones that don't require subscriptions or suffer from &lt;a href="https://en.wikipedia.org/wiki/Enshittification" rel="noopener noreferrer"&gt;enshitification&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation is Part of Development
&lt;/h2&gt;

&lt;p&gt;I updated the &lt;a href="https://github.com/dannagle/PacketSender/pull/419/changes#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5" rel="noopener noreferrer"&gt;README&lt;/a&gt; to include all the HTTP verbs that PacketSender will support once my PR is merged.&lt;/p&gt;

&lt;p&gt;And I included an example request for each of the new verbs. However, you'll only get the new packets on a fresh install or if you delete the packet database. Perhaps I could add an enhancement  that would add those packets if they didn't already exist. Reach out if you'd like for me to add a feature that will update the list of packets automagically when PackeSender starts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd7in7v2obay1rr63jwc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd7in7v2obay1rr63jwc6.png" alt=" " width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with Qt Designer
&lt;/h2&gt;

&lt;p&gt;This was the first time I had worked with Qt Designer. Being entirely unfamiliar with the tool, I thought I was going to have a steep learning curve.&lt;/p&gt;

&lt;p&gt;I must admit that when I first looked at the interface in Qt Designer, I wasn't sure how to add the new verbs and protocols to the  dropdown list along with their associated icons. Adding the entries was easy enough: double-click on the drop down, highlight the row you want to add your new entry under and click the plus sign.&lt;/p&gt;

&lt;p&gt;So far, so good.&lt;/p&gt;

&lt;p&gt;But the icon was tricker.&lt;/p&gt;

&lt;p&gt;See, if you click the three dots, it opens a dialog that gives you a list of icons to choose from. But that list doesn't contain icons that are already in the UI you're designing. It's a list of, from what I can tell, generic icons.&lt;/p&gt;

&lt;p&gt;I couldn't find a way to get a dialog that would allow me to upload an icon.&lt;/p&gt;

&lt;p&gt;It turns out this "one weird trick..."&lt;/p&gt;

&lt;p&gt;While working on a relatively &lt;a href="https://github.com/dannagle/PacketSender/pull/413" rel="noopener noreferrer"&gt;large effort&lt;/a&gt; to fix &lt;a href="https://github.com/dannagle/PacketSender/issues/151" rel="noopener noreferrer"&gt;a reported bug&lt;/a&gt;, I learned that Qt has a system called, creatively enough, the &lt;a href="https://doc.qt.io/qt-6/resources.html" rel="noopener noreferrer"&gt;QT Resource System&lt;/a&gt;. In a sentence, the Qt Resource System adds files to your executable so you only have the one file to distribute.&lt;/p&gt;

&lt;p&gt;On a meta level, this is similar to how SQLite gets compiled into your binary.&lt;/p&gt;

&lt;p&gt;As you can see in the screenshot above, you have the option to both copy and paste a resource path for a file that is part of Qt's Resource System. Following &lt;a href="https://imgs.xkcd.com/comics/tech_support_cheat_sheet.png" rel="noopener noreferrer"&gt;this flowchart&lt;/a&gt;, I learned this part of Qt Designer. Q Designer, in turn, updates &lt;code&gt;.ui&lt;/code&gt; files in the project. &lt;code&gt;.ui&lt;/code&gt; files are renamed xml documents with. &lt;code&gt;.ui&lt;/code&gt; extension, and thus suitable for version control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sprinkling in a bit of Surprise and Delight
&lt;/h2&gt;

&lt;p&gt;As part of the PR, I added a feature to solve an annoyance of mine while manually testing my changes.&lt;/p&gt;

&lt;p&gt;As I'm sure most of you who have read this far know, HTTP and HTTPS have default ports. What was annoying to me was switching between HTTP and HTTPS (and the other way around) meant having to manually change the port numbers.&lt;/p&gt;

&lt;p&gt;I immediately thought there had to be a better user experience...and I created one!&lt;/p&gt;

&lt;p&gt;Now, if you currently have selected an HTTP request type and switch to an HTTPS request type AND the port is the default HTTP port of &lt;code&gt;80&lt;/code&gt;, when you switch to HTTPS, I update the port to &lt;code&gt;443&lt;/code&gt;. Likewise, if you're currently on an HTTPS request type with the default port of 443 and switch to an HTTP request type, I change the port to &lt;code&gt;80&lt;/code&gt;. Saves the user from having to update the port.&lt;/p&gt;

&lt;p&gt;I didn't formally document this feature outside of what you just read and explaining it in the &lt;a href="https://github.com/dannagle/PacketSender/pull/419/" rel="noopener noreferrer"&gt;PR&lt;/a&gt;. The commit is &lt;a href="https://github.com/ProfessorTom/PacketSender/commit/3288971bf0f085eb6c6cd0a2ba44dfe9b594b672" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you want to see the code.&lt;/p&gt;




&lt;p&gt;This was a fun PR to work on. If you found any of this useful or want to support continued improvements to PacketSender, you can &lt;a href="https://www.paypal.com/paypalme/realprofessortom" rel="noopener noreferrer"&gt;donate via PayPal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’m also open to new opportunities; feel free to reach out.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>networking</category>
      <category>http</category>
    </item>
    <item>
      <title>Why Your Browser Won't Open Maps with a geo: URI (And a Workaround)</title>
      <dc:creator>Tomas Gallucci</dc:creator>
      <pubDate>Mon, 07 Jul 2025 21:08:21 +0000</pubDate>
      <link>https://dev.to/professortom/why-your-browser-wont-open-maps-with-a-geo-uri-and-a-workaround-ief</link>
      <guid>https://dev.to/professortom/why-your-browser-wont-open-maps-with-a-geo-uri-and-a-workaround-ief</guid>
      <description>Cover Photo by &lt;a href="https://unsplash.com/@geojango_maps?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;GeoJango Maps&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/person-holding-red-round-medication-pill-Z8UgB80_46w?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
Mapping software has existed for years on machines connected to the internet, be that in apps or websites. (Remember printing out directions from &lt;a href="https://www.mapquest.com/" rel="noopener noreferrer"&gt;Mapquest&lt;/a&gt;?)&lt;/p&gt;

&lt;p&gt;On mobile (read phones and tablets), we have Google Maps, Apple Maps or Waze. Desktop is trickier because neither Windows or Linux come with default, client-side mapping software. macOS, however, does come with (Apple) Maps.&lt;/p&gt;

&lt;p&gt;It would be nice if, on websites, we could create one link that had enough data in it that it could open a default app or website for people to get driving directions. In other words, not a link to Google Maps. Not a link to Apple Maps. Just enough metadata for the browser to open the mapping software of the user’s choice.&lt;/p&gt;
&lt;h2&gt;
  
  
  Defining the Problem
&lt;/h2&gt;

&lt;p&gt;First, some definitions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;URL&lt;/strong&gt;, an acronym that stands for &lt;strong&gt;U&lt;/strong&gt;niform &lt;strong&gt;R&lt;/strong&gt;esource &lt;strong&gt;L&lt;/strong&gt;ocator, best known as web links. URLs have the following format:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[scheme]://[host]/[path]?[query]#[fragment]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If we take a web address, say &lt;code&gt;https://apple.com&lt;/code&gt;, we can see that there is a scheme (&lt;code&gt;https&lt;/code&gt;) and a host (&lt;code&gt;apple.com&lt;/code&gt;). We can omit a path because web servers will provide a default path even if one is not specified. But if we want a specific resource from the domain, then we would add the path. For example, if we want to look at the iPhone page, we would specify &lt;code&gt;https://www.apple.com/iphone/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It turns out that URLs are a highly familiar form of a &lt;strong&gt;URI&lt;/strong&gt; or &lt;strong&gt;U&lt;/strong&gt;niform &lt;strong&gt;R&lt;/strong&gt;esource &lt;strong&gt;I&lt;/strong&gt;dentifier. A URI is a string of characters that identifies a resource, either by its location, name, or both, in a standardized way. URIs are structured like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[scheme]:[scheme-specific-part][#fragment]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the format of a URI is a more generic form of a URL. &lt;/p&gt;
&lt;h2&gt;
  
  
  URI Schemes in Action
&lt;/h2&gt;

&lt;p&gt;With a URL, the scheme part of the URI is also the protocol that is to be used e.g. &lt;code&gt;http&lt;/code&gt; or &lt;code&gt;https&lt;/code&gt;. Web browsers handle both of these protocols because web sites run on the &lt;strong&gt;H&lt;/strong&gt;ype*&lt;em&gt;t&lt;/em&gt;&lt;em&gt;ext **T&lt;/em&gt;&lt;em&gt;ransfer **P&lt;/em&gt;*rotocol. HTTP protocol; HTTPS adds encryption or the "security" the "S" stands for in the acronym.&lt;/p&gt;

&lt;p&gt;It turns out that there are URIs that are useful for other things like creating a link to a phone number or an email address. For example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;”tel:2595556455”&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Might Actually be a Valid Phone Number&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will render like this: &lt;a href="%E2%80%9Dtel:2595556455%E2%80%9D"&gt;Might Actually be a Valid Phone Number&lt;/a&gt;. If you were to click or tap the link, your device will try to place a phone call to &lt;code&gt;2595556455&lt;/code&gt; with some kind of telephony app. For iOS, this would be the phone app that comes pre-installed on the phone. (You can change the default to FaceTime; Zoom is also an option if installed, but Signal is not.) There are also default dialers for Androids of all kinds. And it's possible that you could default to an app like Signal.&lt;/p&gt;

&lt;p&gt;On macOS, FaceTime will open if you click on a link that has a &lt;code&gt;tel:&lt;/code&gt; URI scheme.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;”mailto:janedoe@spamspamspam.com”&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Totally Legit Email&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will render like this: &lt;a href="%E2%80%9Dmailto:janedoe@spamspamspam.com%E2%80%9D"&gt;Totally Legit Email&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you were to click or tap &lt;em&gt;that&lt;/em&gt; link, your default email client would open on both desktop and mobile.&lt;/p&gt;

&lt;p&gt;What if there was a URI scheme that could do the same for addresses?&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;loc:&lt;/code&gt; URI Scheme
&lt;/h2&gt;

&lt;p&gt;What many web programmers don’t know is that there is a &lt;a href="https://en.wikipedia.org/wiki/Geo_URI_scheme" rel="noopener noreferrer"&gt;geolocation URI scheme&lt;/a&gt; that has been defined since 2010. Here are two examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;”geo:112.0,-112.0;u=35”&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Example of a Geolocation Tag&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"geo:0,0?q=1600+Pennsylvania+Ave+NW,+Washington,+DC+20500"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"noopener"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;1600 Pennsylvania Ave NW, Washington, DC 20500&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first example, what follows &lt;code&gt;geo:&lt;/code&gt; is latitude and longitude coordinates with an optional “uncertainty” radius parameter defined by the &lt;code&gt;u=35&lt;/code&gt;. In the second example, we see we can zero out the lat and long and use a mailing address instead.&lt;/p&gt;

&lt;p&gt;This seems like nirvana, one geolocation URI scheme to rule them all!&lt;/p&gt;

&lt;p&gt;Unfortunately, not all is well in Elsinore.&lt;/p&gt;

&lt;h2&gt;
  
  
  It Doesn't Really Work
&lt;/h2&gt;

&lt;p&gt;The only device that seems to support it half way decently, is a major browser (i.e. Firefox) on an Android phone.&lt;/p&gt;

&lt;p&gt;The major reason that &lt;code&gt;geo:&lt;/code&gt; URI schemes don't work is that the browsers don't register handlers for the URI schemes.&lt;/p&gt;

&lt;p&gt;We'll show you a lame workaround towards the end of this post that relies on browsers not handling the &lt;code&gt;loc:&lt;/code&gt; URI scheme throwing an error that can be handled in a &lt;code&gt;try/catch&lt;/code&gt;, but it turns out even that doesn't work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firefox, Chrome, and Safari don’t even recognize the thing, apparently
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Firefox
&lt;/h3&gt;

&lt;p&gt;&lt;/p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8f3yzitx3z052mkzg60.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8f3yzitx3z052mkzg60.png" alt="Firefox console when clicking an `&lt;a&gt;` with a `geo:` URI scheme" width="761" height="52"&gt;&lt;/a&gt;Firefox console when clicking an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; with a &lt;code&gt;geo:&lt;/code&gt; URI scheme&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The fact that this is not an error means that it cannot be handled simply by a try / catch fallback on Firefox. It must have a more robust device agent checking solution that “fixes” Firefox's shortcomings. The good news is that Firefox's marketshare is dwindling, so this browser may not have to be supported for long.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chrome
&lt;/h3&gt;

&lt;p&gt;&lt;/p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wcax0bpnjziitmm9l7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wcax0bpnjziitmm9l7s.png" alt="Chrome console when clicking an `&lt;a&gt;` with a `geo:` URI scheme" width="800" height="56"&gt;&lt;/a&gt;Chrome console when clicking an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; with a &lt;code&gt;geo:&lt;/code&gt; URI scheme&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;You might expect that Chrome would open a new tab or window to Google Maps with the specified latitude and longitude or physical address. Instead, the behavior is a silent console error with no message presented to the end-user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Safari
&lt;/h3&gt;

&lt;p&gt;Safari's behavior on both desktop is even more baffling, especially given that Safari only runs on Apple's OSes &lt;strong&gt;and&lt;/strong&gt; Apple has their own, first-party mapping software!&lt;/p&gt;

&lt;h4&gt;
  
  
  Safari Desktop
&lt;/h4&gt;

&lt;p&gt;&lt;/p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cljiwwi9z8p6mgx4rj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cljiwwi9z8p6mgx4rj8.png" alt="Safari desktop alert when clicking an `&lt;a&gt;` with a `geo:` URI scheme" width="800" height="295"&gt;&lt;/a&gt;Safari desktop alert when clicking an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; with a &lt;code&gt;geo:&lt;/code&gt; URI scheme&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;On the desktop, at least Safari gives a browser alert in addition to throwing an error. But, as pointed out above, this makes absolutely no sense–why doesn't Apple at lest register &lt;code&gt;geo:&lt;/code&gt; with Safari and either ask or attempt to open the location in Apple Maps?&lt;/p&gt;

&lt;p&gt;Perhaps Apple has avoided doing this to avoid an anti-trust/anti-competition lawsuit. This seems fixable with a setting, but as we will see, even on mobile Apple hasn't properly solve this problem.&lt;/p&gt;

&lt;h4&gt;
  
  
  Safari Mobile
&lt;/h4&gt;

&lt;p&gt;&lt;/p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpkimyuymp35xt5coljl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpkimyuymp35xt5coljl.jpg" alt="Safari desktop alert when clicking an `&lt;a&gt;` with a `geo:` URI scheme" width="739" height="1600"&gt;&lt;/a&gt;Safari mobile alert when clicking an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; with a &lt;code&gt;geo:&lt;/code&gt; URI scheme&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Tapping on a link that has a &lt;code&gt;geo:&lt;/code&gt; URI scheme on iOS 18.5 on an iPhone 16 Pro doesn't try to open Apple Maps nor Google Maps, both of which are installed. Instead, mobile Safari is registered to open location links with Google Earth!&lt;/p&gt;

&lt;p&gt;To add insult to injury, maps isn't a category that you can set a default app for, at least not in Default Apps:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzy7lku9kkt08kx3oi3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzy7lku9kkt08kx3oi3q.png" alt="List of defaults that can be changed under Default Apps in iOS 18.5" width="800" height="1732"&gt;&lt;/a&gt;List of defaults that can be changed under Default Apps in iOS 18.5&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Apple has, in times past, sometimes hidden default app settings in Apple's setting for that particular app. For example, you'd go to Safari's settings to change the default web browser. There is no such setting in the (Apple) Maps settings. (&lt;strong&gt;Note&lt;/strong&gt;: I'm not showing the Maps settings here because it's several screens long and there is no default setting in the list of Maps settings.)&lt;/p&gt;

&lt;h2&gt;
  
  
  A Workaround
&lt;/h2&gt;

&lt;p&gt;As promised, here is a workaround. It is a React component that detects browsers that do support &lt;code&gt;loc:&lt;/code&gt; and replaces the anchor with a link to Google Maps if the browser doesn't support the &lt;code&gt;loc:&lt;/code&gt; URI scheme. (&lt;strong&gt;Note&lt;/strong&gt;: This code doesn't know about browser's capabilities; rather, it assumes the programmer knows which browsers do and don't support &lt;code&gt;loc:&lt;/code&gt; URI schemes.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AddressLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;street&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;street&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Invalid address&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;street&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoded_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/%20/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;geoAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`geo:0,0?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;encoded_address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fallbackAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://www.google.com/maps/search/?api=1&amp;amp;query=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;encoded_address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// this will need to be updated for any new mobile devices that exist.&lt;/span&gt;
  &lt;span class="c1"&gt;// it is a regex that tests the current agent against all the agents listed.&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;supportsGeoScheme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sr"&gt;/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;supportsGeoScheme&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;geoAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Attempt geo:&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fallbackAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Fallback to Google Maps&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;geoAddress&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;AddressLink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If this post was helpful, educational or entertaining, please consider converting that help, education or entertainment value into a number and returning it to us:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    &lt;a href="https://www.paypal.com/paypalme/realprofessortom" rel="noopener noreferrer"&gt;&lt;br&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5in6a38sg3gpnackcdz.png" alt="PayPal Donation Button" width="800" height="293"&gt;&lt;br&gt;
    &lt;/a&gt;&lt;br&gt;
&lt;a href="https://buymeacoffee.com/professortom" rel="noopener noreferrer"&gt;&lt;br&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7nlbdbmn1sh66vq5aes.png" alt="Buy Me a Coffee" width="800" height="224"&gt;&lt;br&gt;
    &lt;/a&gt;&lt;br&gt;
  &lt;/p&gt;




&lt;p&gt;Justin Morrow (&lt;a href="https://github.com/JPTomorrow" rel="noopener noreferrer"&gt;github&lt;/a&gt; - &lt;a href="https://www.linkedin.com/in/morrowjustin/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; - &lt;a href="https://x.com/multivac_jm" rel="noopener noreferrer"&gt;X&lt;/a&gt;) contributed to this blog post and will receive partial compensation from donations.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>urischemes</category>
      <category>html</category>
      <category>geolocation</category>
    </item>
    <item>
      <title>Making Tech Lemonade Out of Tech Lemons</title>
      <dc:creator>Tomas Gallucci</dc:creator>
      <pubDate>Fri, 11 Oct 2024 12:30:04 +0000</pubDate>
      <link>https://dev.to/professortom/making-tech-lemonade-out-of-tech-lemons-28ce</link>
      <guid>https://dev.to/professortom/making-tech-lemonade-out-of-tech-lemons-28ce</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/making-tech-lemonade-out-of-tech-lemons-a614b113a6c9?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24yqxel4z71gqf1uw575.png" alt="shitty photo by author" width="800" height="743"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;small&gt;shitty photo by author&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&lt;br&gt;I’ve recently taken a vow of poverty and started spitting into a tube.&lt;/p&gt;

&lt;p&gt;In other words, I’ve recorded a few episodes of podcasts, some which will be released publicly; some which have already turned into “lost tapes”.&lt;/p&gt;

&lt;p&gt;In aid of this effort, I finally got a sound mixer designed for podcasts–the RodeCaster Duo (pictured above).&lt;/p&gt;

&lt;p&gt;Instead of relying on software on one’s computer for recording audio, one can record directly on the RodeCaster Duo if one has a microSD card.&lt;/p&gt;

&lt;p&gt;I ordered a 1TB microSD card from Amazon. When it arrived, I plugged it into my RodeCaster Duo and expected the gray REC icon to have a red ring around it indicating that the Duo was ready to record.&lt;/p&gt;

&lt;p&gt;This did not happen.&lt;/p&gt;

&lt;p&gt;I plugged the microSD card into my MacBook Pro. The MacBook Pro could see the card. Once re-inserted into the RodeCaster Duo, the REC icon refused to don its red ring.&lt;/p&gt;

&lt;p&gt;Rode has a list of recommended microSD cards. They even have a support page for topic Why isn’t my MicroSD card recognised on my RØDECaster Pro II/ Duo. Neither of these pages helped.&lt;/p&gt;

&lt;p&gt;According to a webpage (possibly Reddit) that I can no longer find in my browser’s history, it turns out that the RodeCaster Duo doesn’t recongize high capacity microSD cards. What the highest supported capacity is, I do not know. I will remedy the problem by purchasing something less capacious with the help of a sales person who knows the RodeCaster Duo well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A512%2Fformat%3Awebp%2F0%2A30TkRY-BSsqSrMvR.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A512%2Fformat%3Awebp%2F0%2A30TkRY-BSsqSrMvR.png" width="256" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, since I already had the microSD card and since I had to eviscerate the packaging to get the damned thing out, there was no point trying to haggle a return.&lt;/p&gt;

&lt;p&gt;But all was not lost.&lt;/p&gt;

&lt;p&gt;I bought my MacBook Pro slightly more than a year ago. During that time, I hadn’t started backing the machine up because I didn’t have an external hard drive that was capacious enough to handle the 4 TB of the SSD, much less have capacity to back up more than a full drive.&lt;/p&gt;

&lt;p&gt;Now, I’m nowhere near having a full 4TB of data to back up. But I wanted to make sure that I could have one full back up that size if I needed it. Ergo, I had my eye set on an external 5TB hard drive.&lt;/p&gt;

&lt;p&gt;Why a hard drive (e.g. spinning platters)? Because SSDs and hard drives have different failure rates because of their different physical constitutions. Thus, there would be two opportunities to preserve data at two different retention rates.&lt;/p&gt;

&lt;p&gt;&lt;br&gt; ## Multiple Backups&lt;br&gt;
It turns out that you can have multiple backup drives for a single machine in Apple’s Time Machine software–the back up software that ships with every Mac.&lt;/p&gt;

&lt;p&gt;Although I did recently purchase a 5TB external hard drive, it’s bulkier than a microSD card in a SD card adapter. The external hard drive needs to be somewhere flat where there will be no movement. And the hard drive takes longer to back up to because of having to wait for the spinning platter to rotate under the head to write data and then again to read the data back to make sure the write was correct.&lt;/p&gt;

&lt;p&gt;But because the microSD card is faster and more portable, even though its capacity is only 25% of the capacity of the internal SSD, it is more than sufficient for running incremental backups of documents. Ergo, as I build my writing empire, I will have revert points automagically thanks to Time Machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F0%2AoTUPdvpebEdpkBjq" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F0%2AoTUPdvpebEdpkBjq" alt="Photo by [Francesca Hotchin](https://unsplash.com/@franhotchin?utm_source=medium&amp;amp;utm_medium=referral) on [Unsplash](https://unsplash.com/?utm_source=medium&amp;amp;utm_medium=referral)" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;small&gt;Photo by &lt;a href="https://unsplash.com/@franhotchin?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Francesca Hotchin&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/center&gt;

&lt;p&gt;&lt;br&gt;Therefore, I turned a setback (technical lemons) into a win (technical lemonade).&lt;/p&gt;




&lt;p&gt;Find me elsewhere on the internet at &lt;a href="https://linktr.ee/professortom" rel="noopener noreferrer"&gt;https://linktr.ee/professortom&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/making-tech-lemonade-out-of-tech-lemons-a614b113a6c9?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;Originally posted in The Uncoded Developer Publication on Medium.com »&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rodecasterduo</category>
      <category>podcast</category>
      <category>microsdcard</category>
      <category>backupsoftware</category>
    </item>
    <item>
      <title>What Did We Actually Get from the Apple Media Event?</title>
      <dc:creator>Tomas Gallucci</dc:creator>
      <pubDate>Fri, 27 Sep 2024 14:36:22 +0000</pubDate>
      <link>https://dev.to/professortom/what-did-we-actually-get-from-the-apple-media-event-477n</link>
      <guid>https://dev.to/professortom/what-did-we-actually-get-from-the-apple-media-event-477n</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/what-did-we-actually-get-from-the-apple-media-event-e663093bd900?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--13elLuql--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/981/0%2A_9GerPMHJuycOJuz" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wrote an article What I Hope To Get Out of Apple’s Event Today. This is a follow up to that article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/what-did-we-actually-get-from-the-apple-media-event-e663093bd900?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;Continue reading on The Uncoded Developer »&lt;/a&gt;&lt;/p&gt;

</description>
      <category>technology</category>
      <category>apple</category>
      <category>appleintelligence</category>
      <category>iphone</category>
    </item>
    <item>
      <title>How To Solve The Problem of the Vanishing PDF Form Data</title>
      <dc:creator>Tomas Gallucci</dc:creator>
      <pubDate>Thu, 12 Sep 2024 16:16:49 +0000</pubDate>
      <link>https://dev.to/professortom/how-to-solve-the-problem-of-the-vanishing-pdf-form-data-4o1d</link>
      <guid>https://dev.to/professortom/how-to-solve-the-problem-of-the-vanishing-pdf-form-data-4o1d</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/how-to-solve-the-problem-of-the-vanishing-pdf-form-data-bf695107ba99?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pgV-M8y3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2ANemj4osLVbBN_HVh" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What to do if you fill out a pdf on a Mac and the data doesn’t appear on Windows&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/how-to-solve-the-problem-of-the-vanishing-pdf-form-data-bf695107ba99?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;Continue reading on The Uncoded Developer »&lt;/a&gt;&lt;/p&gt;

</description>
      <category>preview</category>
      <category>mac</category>
      <category>forms</category>
      <category>techtips</category>
    </item>
    <item>
      <title>What I Hope To Get Out of Apple’s Event Today</title>
      <dc:creator>Tomas Gallucci</dc:creator>
      <pubDate>Mon, 09 Sep 2024 13:27:23 +0000</pubDate>
      <link>https://dev.to/professortom/what-i-hope-to-get-out-of-apples-event-today-23e4</link>
      <guid>https://dev.to/professortom/what-i-hope-to-get-out-of-apples-event-today-23e4</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/what-i-hope-to-get-out-of-apples-event-today-e3f19322ed24?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u_QMgsHF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/981/0%2A6df7Lse3fzROI7gS" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I want to talk about my personal needs and what I think we’ll likely see announced today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/what-i-hope-to-get-out-of-apples-event-today-e3f19322ed24?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;Continue reading on The Uncoded Developer »&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>apple</category>
      <category>iphone</category>
      <category>ai</category>
    </item>
    <item>
      <title>Review of Kumar S’s “Python Automation Testing With Pytest” Udemy Course</title>
      <dc:creator>Tomas Gallucci</dc:creator>
      <pubDate>Wed, 24 Jul 2024 13:12:25 +0000</pubDate>
      <link>https://dev.to/professortom/review-of-kumar-ss-python-automation-testing-with-pytest-udemy-course-3e4m</link>
      <guid>https://dev.to/professortom/review-of-kumar-ss-python-automation-testing-with-pytest-udemy-course-3e4m</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/review-of-kumar-ss-python-automation-testing-with-pytest-udemy-course-e25a36a9ba18?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BXnAMH-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2600/0%2ADzYl5ocTAnj_5mDG" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most interesting concepts in Pytest were Markers and Fixtures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/the-uncoded-developer/review-of-kumar-ss-python-automation-testing-with-pytest-udemy-course-e25a36a9ba18?source=rss----2955c355db08---4" rel="noopener noreferrer"&gt;Continue reading on The Uncoded Developer »&lt;/a&gt;&lt;/p&gt;

</description>
      <category>automatedtesting</category>
      <category>python</category>
      <category>pytest</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
