<?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: Salvatore Denaro</title>
    <description>The latest articles on DEV Community by Salvatore Denaro (@sdenaro).</description>
    <link>https://dev.to/sdenaro</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%2F3155999%2F4b4494ab-0862-4c52-91f7-bd40d3133fa0.jpg</url>
      <title>DEV Community: Salvatore Denaro</title>
      <link>https://dev.to/sdenaro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sdenaro"/>
    <language>en</language>
    <item>
      <title>Capturing Bluesky bookmarked and favorited items via RSS</title>
      <dc:creator>Salvatore Denaro</dc:creator>
      <pubDate>Mon, 03 Aug 2026 13:17:00 +0000</pubDate>
      <link>https://dev.to/sdenaro/capturing-bluesky-bookmarked-and-favorited-items-via-rss-3d0n</link>
      <guid>https://dev.to/sdenaro/capturing-bluesky-bookmarked-and-favorited-items-via-rss-3d0n</guid>
      <description>&lt;p&gt;Bluesky has become my preferred starting point to check what is trending in the news. Back when I was still using Twitter; way back when it provided a useful free API tier, I had a script that would pull my favorites from Twitter to an RSS feed. &lt;/p&gt;

&lt;p&gt;I recently decided to recreate that for Bluesky. While the old script just provided favorites, the new one provided feeds for both favorited and bookmarked items. I also hacked up a way to deal with multiple accounts. This time, I used FastAPI and python rather than Sinatra and ruby for the old one.&lt;/p&gt;

&lt;p&gt;Why bother? I enjoy bookmarking things to read later and this mechanism lets me pull my bookmarked items into my RSS reader.&lt;/p&gt;

&lt;p&gt;And this time, the code was mostly generated by Gemini 3.1 Pro via Google Antigravity.&lt;/p&gt;

&lt;p&gt;You can check it out &lt;a href="https://github.com/sdenaro/favsandmarks" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>bluesky</category>
      <category>python</category>
      <category>rss</category>
    </item>
    <item>
      <title>Using Google Colab for REST API exploration and testing</title>
      <dc:creator>Salvatore Denaro</dc:creator>
      <pubDate>Mon, 02 Jun 2025 14:13:00 +0000</pubDate>
      <link>https://dev.to/sdenaro/using-google-colab-for-rest-api-exploration-and-testing-18a5</link>
      <guid>https://dev.to/sdenaro/using-google-colab-for-rest-api-exploration-and-testing-18a5</guid>
      <description>&lt;p&gt;New York City's Office of Technology Innovation provides a &lt;a href="https://api-portal.nyc.gov/apis" rel="noopener noreferrer"&gt;collection of useful APIs&lt;/a&gt; that let you access City data. For the past few weeks I have been playing with the APIs looking for useful application ideas and I've been using Google's colab product for that exploration. These APIs are free to access and you can sign up &lt;a href="https://api-portal.nyc.gov/signup" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are new to Colab, Google provides an &lt;a href="https://colab.research.google.com/notebooks/intro.ipynb" rel="noopener noreferrer"&gt;introduction&lt;/a&gt; notebook that covers the basics. If you've used &lt;a href="https://jupyter.org/" rel="noopener noreferrer"&gt;jupyter&lt;/a&gt; with Python you should be good to go. While Colab is frequently used for data science and AI, I think this is a great platform for building internal tools. For one specific type of user, users with lots of domain specific knowledge who may not know an API or tool, Colab is useful as a way of bundling instructions and code in a way that allows them to be productive.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Minimal code example for connecting to an end point
&lt;/h3&gt;

&lt;p&gt;This is a minimal test script. It connects to an API, uses a secure way of holding the API keys and allows the user to visually set the parameters sent to the API. After execution, the JSON output is displayed. While this is fine, an a step above using CURL from the command line, this isn't what I would send to a user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.colab&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;userdata&lt;/span&gt;


&lt;span class="k"&gt;from&lt;/span&gt;\&lt;span class="n"&gt;_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-05-27&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# @param {type: "date"}
&lt;/span&gt;
&lt;span class="n"&gt;to&lt;/span&gt;\&lt;span class="n"&gt;_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-06&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="c1"&gt;# @param {type: "date"}
&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.nyc.gov/public/api/GetCalendar?fromdate={}&amp;amp;todate={}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;api&lt;/span&gt;\&lt;span class="n"&gt;_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;\&lt;span class="n"&gt;_date&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;\&lt;span class="n"&gt;_date&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="n"&gt;subkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userdata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Ocp-Apim-Subscription-Key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ocp-Apim-Subscription-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;\&lt;span class="n"&gt;_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&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://blogger.googleusercontent.com/img/a/AVvXsEg0tXCKEp8vbh1J7JnzO8tZKwicoAtaAgFFFtCDEsagrXL8CfImd-_WNWdqyV5spCHpXMfRr8fnH4dUGWfrZ2wme6GAj-UgzZNxGJ5T4I1QKSagBtoszJSwfYIPxOLqSJi53UKHG0SVPd2dRqv2X4hFPn1BKa5G1b44i8NYQgK4ApvNDYq9c_etd-4nJGej" 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%2Fblogger.googleusercontent.com%2Fimg%2Fa%2FAVvXsEg0tXCKEp8vbh1J7JnzO8tZKwicoAtaAgFFFtCDEsagrXL8CfImd-_WNWdqyV5spCHpXMfRr8fnH4dUGWfrZ2wme6GAj-UgzZNxGJ5T4I1QKSagBtoszJSwfYIPxOLqSJi53UKHG0SVPd2dRqv2X4hFPn1BKa5G1b44i8NYQgK4ApvNDYq9c_etd-4nJGej%3Dw640-h280" width="640" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what it looks like on screen. The left side has the python code while the UI for setting dates is on the right.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storing secrets outside of notebooks
&lt;/h3&gt;

&lt;p&gt;Colab lets you store API keys outside of the code and use a class for accessing the keys. I highly recommend doing this rather than pasting the keys in code. Sharing a Colab notebook does not share the keys so you will need to work with users to have them install API keys but once you install a key, it is usable in any of the notebooks the user has.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/a/AVvXsEj3sEatFpZqO6RD7Pr8vEQHA7sA6bXh-a2-UDBbOHBdGwIBuAH42CJDaAnfOC7YdtrQEeOZbWsN_XOY8e27coa63OT3SJ4PegPzj8gA3_zjWVQl-yioLq2JR2mm01ozlhOJMItw6LHDNtWsv2f9zLpCJnNyDZfgIs2dhuD_Wmnc89u35lbxzBg7BwznTQbo" 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%2Fblogger.googleusercontent.com%2Fimg%2Fa%2FAVvXsEj3sEatFpZqO6RD7Pr8vEQHA7sA6bXh-a2-UDBbOHBdGwIBuAH42CJDaAnfOC7YdtrQEeOZbWsN_XOY8e27coa63OT3SJ4PegPzj8gA3_zjWVQl-yioLq2JR2mm01ozlhOJMItw6LHDNtWsv2f9zLpCJnNyDZfgIs2dhuD_Wmnc89u35lbxzBg7BwznTQbo%3Dw400-h400" width="399" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding exception handling and extracting out the API call
&lt;/h3&gt;

&lt;p&gt;First step is to extract out a function to call the API and to create a short circuit test in case there is no API key set in secrets. After that, we include error handling and the libraries we will be using below. Normally, this is code you would hide and simply execute to set up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.colab&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;userdata&lt;/span&gt;

&lt;span class="c1"&gt;# fail quick if no API Key 
&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;userdata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Ocp-Apim-Subscription-Key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to_date&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.nyc.gov/public/api/GetCalendar?fromdate={}&amp;amp;todate={}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;api_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_date&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_date&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;subkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userdata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Ocp-Apim-Subscription-Key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ocp-Apim-Subscription-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Raise HTTPError for responses 4xx or 5xx
&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
  &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error fetching API: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


  &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error while fetching API: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;json_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json_data&lt;/span&gt;
  &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONDecodeError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error decoding JSON: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using a form for data entry
&lt;/h3&gt;

&lt;p&gt;In the same way you want to avoid putting any API keys in code you should avoid having users edit code to set variables. Colab has a really nice &lt;a href="https://colab.research.google.com/notebooks/snippets/forms.ipynb" rel="noopener noreferrer"&gt;form&lt;/a&gt; system. When combined with the hide code option, you can build a tool where a domain expert can populate a request and execute it without any knowledge of the internals. Avoid having users put API keys in a form. Users might email screenshots or paste them in a bug tracker and they may not be careful about leaking data. &lt;/p&gt;

&lt;p&gt;Below is the block that includes the selection of dates and executes the function call_api.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="n"&gt;from_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-05-27&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# @param {type: "date"}
&lt;/span&gt;
&lt;span class="n"&gt;to_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-03&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# @param {type: "date"}
&lt;/span&gt;
&lt;span class="c1"&gt;# These are the two critical calls
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;json_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have a json response, we can figure out what we want to do with it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Format output data
&lt;/h3&gt;

&lt;p&gt;Colab has a nice data formatter for printing out tables with interactive features. Data can be sorted, filtered and exported via markdown. Overall, it's a pretty good feature set for basic reporting.&lt;br&gt;&lt;br&gt;
At this point the user has a way of executing the set up and then alternating between picking dates and using an interactive table. This is fine assuming all is well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build interactive table
&lt;/h2&gt;

&lt;p&gt;from pandas import DataFrame as df &lt;/p&gt;

&lt;p&gt;from google.colab import data_table&lt;/p&gt;

&lt;p&gt;data_table.disable_dataframe_formatter()&lt;/p&gt;

&lt;p&gt;table = []&lt;/p&gt;

&lt;p&gt;for day in json_data["days"]:&lt;/p&gt;

&lt;p&gt;for item in day["items"]:&lt;/p&gt;

&lt;p&gt;item["day"] = day["today_id"]&lt;/p&gt;

&lt;p&gt;table.append(item)&lt;/p&gt;

&lt;p&gt;df = df(table)&lt;/p&gt;

&lt;p&gt;order = ['day', 'type', 'status', 'details', 'exceptionName']&lt;/p&gt;

&lt;p&gt;df = df.reindex(columns=order)&lt;/p&gt;

&lt;p&gt;df&lt;/p&gt;

&lt;p&gt;You end up with a table like this. While not a full featured spreadsheet, it allows for a fair amount of manipulation of the data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/a/AVvXsEgjXgw5nlpY0aR4zQZOhrse1r2Dqcxz4KfdQ7fsMOkzl_m8UbmRral4SC1T2LUR_7zS85qoMFI_yECKqCXYhi99Hv8fd7Y3oMawQ9RNfJI88AbejCzbWO67aJq04-TpAp6svkdqLG72hfCPKvPw_GfUVj3bQJieBCM_noK2yzs4xj4MKhRk1ssRioHaNuRB" 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%2Fblogger.googleusercontent.com%2Fimg%2Fa%2FAVvXsEgjXgw5nlpY0aR4zQZOhrse1r2Dqcxz4KfdQ7fsMOkzl_m8UbmRral4SC1T2LUR_7zS85qoMFI_yECKqCXYhi99Hv8fd7Y3oMawQ9RNfJI88AbejCzbWO67aJq04-TpAp6svkdqLG72hfCPKvPw_GfUVj3bQJieBCM_noK2yzs4xj4MKhRk1ssRioHaNuRB%3Dw640-h245" width="640" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Building tests
&lt;/h3&gt;

&lt;p&gt;It's nice when things work nicely but that isn't always the case and in almost all cases, the time it &lt;/p&gt;

&lt;p&gt;Pytest is a great tool for testing and I use it for most the of the Python scripts I write. And while it is possible to run pytest in Colab, I normally wouldn't bother. The process for using it exceeds the value I get so I normally just use exception handlers for critical code where I need to know the cause of a failure and simple boolean evaluations to "test" the results of my code. &lt;/p&gt;

&lt;p&gt;In this notebook I have loud errors for the three blockers that a user might encounter, lack of a security key, the API not responding and the API not returning JSON. In cases where everything runs but the chart can not be populated, I section called Test Results Dump.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Testing and reporting errors
&lt;/h3&gt;

&lt;p&gt;The general form for testing software is Given, When, Expect. I don't remember where I learned that from but whenever I am writing tests, I keep those three words in that order in my head. &lt;/p&gt;

&lt;p&gt;If I am given a URL, when I call the URL with these values I expect the following outcomes. In order to follow that best practice I need to rewrite the code to extract out some functions and break the code down into sections that can be executed individually. The section that calls the API and then runs the tests should be able to executed multiple times with different inputs. And it should be possible to export the results in a way that could be attached to a bug tracking system. &lt;/p&gt;

&lt;p&gt;Normally I would follow the &lt;a href="https://wit-computing-msc-2017.github.io/agile/topic07-tdd-3-and-pacemaker-solution//talk-2-right-bicep/b-bicep.pdf" rel="noopener noreferrer"&gt;Right Bicep&lt;/a&gt; rules but I am only going to test the three things that would break my use case, which is a script to automatically add exceptions to my calendar. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;That there is a collection of items under "days" that is equal to the date range between from and to.&lt;/li&gt;
&lt;li&gt;That for any day, there are three items-Alternate Side Parking, Collections and Schools.&lt;/li&gt;
&lt;li&gt;If schools are closed, or trash pick up is delayed or suspended or alternate sides parking is suspended, that there is a non empty exception for the item.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Dumping test output
&lt;/h3&gt;

&lt;p&gt;Executing the code in the Test Results Dump results in executing some test code that inspect the JSON that is returned to see if it conforms with the expectations. If a field is renamed or some other data is added then one or more tests will fail and hopefully lead to information that is useful in mitigating any issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dump Out Test Table
&lt;/h2&gt;

&lt;h2&gt;
  
  
  This is a row by row test dump, run this if you dont' get the pretty data report
&lt;/h2&gt;

&lt;p&gt;print(f"from_date: {from_date}")&lt;/p&gt;

&lt;p&gt;print(f"to_date: {to_date}")&lt;/p&gt;

&lt;p&gt;print(test_not_empty(response.text))&lt;/p&gt;

&lt;p&gt;print(test_not_empty(json_data))&lt;/p&gt;

&lt;p&gt;print(test_date_range(json_data["days"],from_date,to_date))&lt;/p&gt;

&lt;h1&gt;
  
  
  this should be a parameterized test
&lt;/h1&gt;

&lt;p&gt;for day in json_data["days"]:&lt;/p&gt;

&lt;p&gt;print(day)&lt;/p&gt;

&lt;p&gt;for item in day["items"]:&lt;/p&gt;

&lt;p&gt;print(test_item(item))&lt;/p&gt;

&lt;p&gt;This results in a blob of test that can be opened in an editor. While it isn't pretty, it can be read.&lt;/p&gt;

&lt;h3&gt;
  
  
  The bonus round
&lt;/h3&gt;

&lt;p&gt;This is a list of items that I may not be needed but I think are worth mentioning.&lt;/p&gt;

&lt;h4&gt;
  
  
  Charts
&lt;/h4&gt;

&lt;p&gt;Colab can make use of matplotlib and Seaborn for &lt;a href="https://colab.research.google.com/notebooks/charts.ipynb#scrollTo=QSMmdrrVLZ-N" rel="noopener noreferrer"&gt;charting&lt;/a&gt;. While not useful for me in this case, you can quickly create a chart like this. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/a/AVvXsEif1m-cM2CBsijYG4V_tRWvcBZilfjJAb9D80TkUCpy3fc1mw1PABeqAdpkCStSfz14d3Y5Yn1ismCVyVDGJGGONHI9oy29KOaf7f93izT5J75kAEm-Udy1Wa7HmOy4IzN5sV1vGbdSca_e2gljxVosNhzDfaJW9DNZwZMf07wEJsckvUenINTZxlWQ8JwQ" 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%2Fblogger.googleusercontent.com%2Fimg%2Fa%2FAVvXsEif1m-cM2CBsijYG4V_tRWvcBZilfjJAb9D80TkUCpy3fc1mw1PABeqAdpkCStSfz14d3Y5Yn1ismCVyVDGJGGONHI9oy29KOaf7f93izT5J75kAEm-Udy1Wa7HmOy4IzN5sV1vGbdSca_e2gljxVosNhzDfaJW9DNZwZMf07wEJsckvUenINTZxlWQ8JwQ" width="658" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Working with Google Sheets
&lt;/h4&gt;

&lt;p&gt;Colab can import and export from &lt;a href="https://colab.research.google.com/notebooks/snippets/sheets.ipynb#scrollTo=6d0xJz3VzLOo" rel="noopener noreferrer"&gt;Google Sheets&lt;/a&gt;. I've used this feature to turn Colab into a report generation tool more than once. I've used it to add rows, columns and new workbooks as a way to keep up to date metrics.&lt;/p&gt;

&lt;p&gt;The example I am using requires saving a JSON file with Auth information to your Google Drive. If you'd rather not use that approach, I wouldn't blame you as its the equivalent of storing ssh keys in your Google drive.&lt;/p&gt;

&lt;p&gt;In those cases, look at the bottom of the data table for this button. It will walk you through creating a live interactive Google Sheet embedded in your notebook.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/a/AVvXsEiSOMmBS43xQvtKgCiwpraxV5wLBR0dQwLpQRXG67ztm_zzLQs7C0kaBl2zCDcQeNAEpbTgoEnUubse7KKoGbcNTUQLtp3eUFQAtRZ_8_YrxsJ3xNGyicAgmz_NET08rBy-QfySs8IMDpai8ZHifJJcMl0_DVOy5iJAWXiJFCtP0WmoQOR0Di3WU1wNfSep" 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%2Fblogger.googleusercontent.com%2Fimg%2Fa%2FAVvXsEiSOMmBS43xQvtKgCiwpraxV5wLBR0dQwLpQRXG67ztm_zzLQs7C0kaBl2zCDcQeNAEpbTgoEnUubse7KKoGbcNTUQLtp3eUFQAtRZ_8_YrxsJ3xNGyicAgmz_NET08rBy-QfySs8IMDpai8ZHifJJcMl0_DVOy5iJAWXiJFCtP0WmoQOR0Di3WU1wNfSep%3Dw200-h54" width="200" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Using custom runtimes
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/a/AVvXsEjBAvtwq6Oh4bRhTh3MYNsNoDZwVfKDflgl7kntliBLrKKikWLoNTKBF8uRd6UUeW-T3C5Q4DGx5FON_8UhMKvfblaU3T9e8el_aI6Hc2aR7Lold31ndMe5Wj8Fiq6DuGXe03_jTY7SZiC-zksO-wMj1fslOioQCtgbgYkLTCpCwszHEv5-hNwIpc-gY8KZ" 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%2Fblogger.googleusercontent.com%2Fimg%2Fa%2FAVvXsEjBAvtwq6Oh4bRhTh3MYNsNoDZwVfKDflgl7kntliBLrKKikWLoNTKBF8uRd6UUeW-T3C5Q4DGx5FON_8UhMKvfblaU3T9e8el_aI6Hc2aR7Lold31ndMe5Wj8Fiq6DuGXe03_jTY7SZiC-zksO-wMj1fslOioQCtgbgYkLTCpCwszHEv5-hNwIpc-gY8KZ" width="678" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you use Google Cloud, you can set up a Compute Engine instance as your back end. This is useful in cases where you have a secure cloud environment and you would like to a access the databases, APIs and other resources while using the same security.&lt;/p&gt;

&lt;h4&gt;
  
  
  Running a local copy
&lt;/h4&gt;

&lt;p&gt;Colab allows you to export a notebooks to, and import a notebook from, GitHub. You can grab a copy of this example from &lt;a href="https://github.com/sdenaro/notebooks" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Both Visual Studio Code and IntelliJ have Python plugins that will execute Python notebooks. You'll have to adjust the way you store keys and remove the Google specific libraries but the notebook would run as expected. &lt;/p&gt;

&lt;h3&gt;
  
  
  Hope this is useful.
&lt;/h3&gt;

&lt;p&gt;If you found this useful and want to encourage me to write more, feel free to comment either here or where ever you found this.&lt;/p&gt;

</description>
      <category>colab</category>
      <category>googlecolab</category>
      <category>nycoti</category>
      <category>programming</category>
    </item>
    <item>
      <title>Setting up Twitter Cards in Blogger</title>
      <dc:creator>Salvatore Denaro</dc:creator>
      <pubDate>Sat, 05 Jun 2021 05:25:00 +0000</pubDate>
      <link>https://dev.to/sdenaro/setting-up-twitter-cards-in-blogger-lff</link>
      <guid>https://dev.to/sdenaro/setting-up-twitter-cards-in-blogger-lff</guid>
      <description>&lt;p&gt;There are plenty of blog posts explaining how to add Twitter Card integration to your Blogger posts but I haven't seen any that are written for the newer Blogger UI. The code that does the integration hasn't changed since this &lt;a href="https://blogger-hints-and-tips.blogspot.com/2013/09/how-to-set-up-twitters-view-summary.html" rel="noopener noreferrer"&gt;article in 2013&lt;/a&gt;, but the steps to add it to your theme have. &lt;/p&gt;

&lt;p&gt;If you haven't logged onto Blogger, do so. You should see this panel on your left.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjet5CH0d9U-nI0_PdVNHEPKNm_XDXs3D6xjhpDbCYjbMucsGQMqKdHPj7P8T4BLiSOnKchsjYSC_GmVX32TIw0EVUlCURieAfKrsU7Fjirw4oFDttfN9FGWyaCzoJ0HZeM5a4EnGWCOfA/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Forzvsungos4880izcr7v.png" width="333" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pick "Theme" and you will see something that looks like this on the top portion of your screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl9kdsGigC516pk0zhn6m92IFagrSVVH3PsROqmn5NV6u8twzUjF3PO6e75Rf0s0gm5NRzF8l7WhAWBFKB3uK3XFTTbesGqiZmrnCXPIV-MPuzE4t1MCn1d_ruRTAO9U5RZjugGrQG-6I/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgxn0p3do7hwwswf5kzik.png" width="640" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First things first, make a backup. Click on the little arrow&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiwBVy82Vs-45N0QWuyPjIvrA81wU8WUvUf1mwSb1dwiqImxNSIs2uPoMdU_zOd9WmU1vUn-izT8mvu5S2JlYLB1o35zY8Fs29QrYU9JkPgVeKprPNhGO4i5OgNjAVe8k32Epv1a5HaT0/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhw6ns9ol8bxl6rcx91z.png" width="640" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are using the classic themes, it will look like this. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqnWLDEthg05sT0XEavsr4ksFABvYla-reWdrb5imK7iQNclcaB985iveQn-TRj64EQqIWox_zEyqyYmCIeyBdPD3lhK7pSNwhjdOaUcvluM5NUD-1aZJvFy3_CiJV-gPY3UR9zt3WmcA/" 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%2Fblogger.googleusercontent.com%2Fimg%2Fb%2FR29vZ2xl%2FAVvXsEiqnWLDEthg05sT0XEavsr4ksFABvYla-reWdrb5imK7iQNclcaB985iveQn-TRj64EQqIWox_zEyqyYmCIeyBdPD3lhK7pSNwhjdOaUcvluM5NUD-1aZJvFy3_CiJV-gPY3UR9zt3WmcA%2F" width="422" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking on the arrow, pick Backup. Download the file. It's the same for classic themes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqKW6Ou69ulp72DfCcNp26qySS-Ao79ldKgCllbMrDPaVuHiC7VkEHaLbJYJJ8Z4VIgBfIUoEZehxAX3m-LssqQ_B0jnNUG0C0PhxVDiQtcQ-sz_foCQ9BSxOU0PV1jOJ7P_Dgyd1qoPA/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm491dytxkiylpu97woff.png" width="640" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pick download. Save the file somewhere just in case you need to recover your theme. While editing your theme will not destroy any of your pages or posts, it can cause problems for the theme you are using if you make a mistake. If you've spent some time editing your blogroll and customizing your colors and fonts, you don't want to lose this so make sure you make a backup.&lt;/p&gt;

&lt;p&gt;Now that you have a backup, pick Edit HTML. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgERZV3XBjZlMD11rLYVvJRy6B9QpHi542NXJKmNmpXLzJseWlaBzJIdWKFcs71MhZ9zssR0bSSwE3PnA4MqeUq3-7eIsws2ZSLZtKxC51L1OtaFaeULNr1LzsgOpUpdztprVRhxVjasvI/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp6edhoad699b5o399axl.png" width="640" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are using the classic theme, click on EDIT HTML button rather than activate the context menu from the drop down.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqnWLDEthg05sT0XEavsr4ksFABvYla-reWdrb5imK7iQNclcaB985iveQn-TRj64EQqIWox_zEyqyYmCIeyBdPD3lhK7pSNwhjdOaUcvluM5NUD-1aZJvFy3_CiJV-gPY3UR9zt3WmcA/" 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%2Fblogger.googleusercontent.com%2Fimg%2Fb%2FR29vZ2xl%2FAVvXsEiqnWLDEthg05sT0XEavsr4ksFABvYla-reWdrb5imK7iQNclcaB985iveQn-TRj64EQqIWox_zEyqyYmCIeyBdPD3lhK7pSNwhjdOaUcvluM5NUD-1aZJvFy3_CiJV-gPY3UR9zt3WmcA%2F" width="422" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see some scary looking HTML code in a code editor. Click anywhere in the code editor. Once you do that, you need to activate search. If you are using a Mac, pick command-F to search. On windows it should be control-F. &lt;/p&gt;

&lt;p&gt;If you see this search box, you did it correctly. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNsXDC-xRcY3k9_AXcYWgmtXEUhxE82HPwVB1hw5dcshHRK_wuEOK-5XnVRGAe-MNyCxE0ierx5BLVErxRAux5vCg6XeclFgtftYGZUdzLAbapCaeJIWw8wb0eSkqU-M7TEwcBCdwxpa4/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffil6840yqlgzepjlx6ol.png" width="640" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you see the browser search box, you didn't click in the code editor. Close the browser's search pop up and then click in the code editor and try the search command again. &lt;/p&gt;

&lt;p&gt;Search for &lt;strong&gt;&lt;/strong&gt; by typing that and then hitting enter. This will search for the bottom of the head element. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMMmj6Ondbq7lq8dSIhrC5pjJwtBwJ5jTeP_0H8lqTYSijP9FojMXeg-WOyxyDk5K3hlR2Vo1YEJ8n7Eb6XWB6k0lIndyy6McWJn1SA9oCy6EUkyGf2fj6Rhicvu_XrnYbzVhQK8Np2g0/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fewwrs7zfes2h1l43krnb.png" width="640" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you see something like this, you are in the right spot. You should see the  tag, which marks the end of the page's head portion and the start of the body of the web page. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdSSZnSygaCKXfAu4eoVflzlYxmtaPg2F7iYHm023iIf4kllNiJ4Ws6sur5Ew8zG8MK5RQBDsxoJyhvA1lEEluO7SCj_7Wx1_aCgtE3bI1BOfv-xciDoYNGZ0KiUPK3jED9iTdjIBskak/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo00hb4vp7t3zpaw9yjq7.png" width="640" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you need to copy over the text . Copy it from the block below. &lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&amp;lt;!--  START - TWITTER CARD TAGS   --&amp;gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
   &lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;a href="/b:if"&gt;/b:if&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/b:if"&gt;/b:if&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&amp;lt;!-- Still looking for a way to use the post snippet if there's no description --&amp;gt;&lt;a href="/b:if"&gt;/b:if&lt;/a&gt;  &lt;/p&gt;




&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;Following the instructions from this &lt;a href="https://blogger-hints-and-tips.blogspot.com/2013/09/how-to-set-up-twitters-view-summary.html" rel="noopener noreferrer"&gt;article in 2013&lt;/a&gt; you need to edit the following.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YOUR-BLOG-URL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This the full URL for the blog. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;URL-FOR-IMAGE-YOU-WANT-TO-USE-IF-THERE-IS-NOT-A-THUMBNAIL-PHOTO-IN-THE-POST&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is an image to use when there is no image in the article. You can pick an image previously uploaded to your blog or your Twitter profile image. I removed that block for this blog by deleting this entire section:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="/b:if"&gt;/b:if&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And lastly, the optionally  &lt;strong&gt;YOUR-TWITTER-ACCOUNT-NAME&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can remove that line if you do not want to use it. &lt;/p&gt;

&lt;p&gt;This is what it looks like on this blog. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQuAjomIhUNWA9u-vrlLzoYSJvs3ZxSE-U4H-y_Fffe0xGuuATCYmwRc24T8VO3zzJ0M7VRvC60RFiePMa8-Eq40hj0BKw3RmIl79YfcBUqynePZi-oTQP0T0VQZ8Nquhwm8EFr95ry6M/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2puokibdm2saism2zejm.png" width="640" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The text needs to be inserted before the &lt;strong&gt;&lt;/strong&gt; tag as the code will only work properly in the page header and not in the page body.&lt;/p&gt;

&lt;p&gt;When you are done making those edits, click on the floppy icon to save. It is on the top right corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoXbP3RKJR0EVPbeoWtIiDbJNHzNZ52R85_4voCqU1S-_zmSB1-RWUNa6-BmvyAN_j60eG9V-ZPuLLLlWlzBX2wUo5qt5KQBhfE3NK9x1Z6EYO-M_WYBJXNtA_Y9bj6031VTrtuBPxDGw/" 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%2Fblogger.googleusercontent.com%2Fimg%2Fb%2FR29vZ2xl%2FAVvXsEjoXbP3RKJR0EVPbeoWtIiDbJNHzNZ52R85_4voCqU1S-_zmSB1-RWUNa6-BmvyAN_j60eG9V-ZPuLLLlWlzBX2wUo5qt5KQBhfE3NK9x1Z6EYO-M_WYBJXNtA_Y9bj6031VTrtuBPxDGw%2F" width="728" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click on the arrow in the top left to go back to the dashboard screen. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_1uvC3IBgv1lr7Tx_sjpxj_sZ5q3O7I51myyzrE4E-lQdIt-238cU7wVtRbLn0-blk1U5jvlCTDfIXFDplAhKqS-PenCKVMmqcxQPbI7TUd9zE5e1V1E3qppPwKPhTHQuAdoQaTdHmWQ/" 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%2Fblogger.googleusercontent.com%2Fimg%2Fb%2FR29vZ2xl%2FAVvXsEj_1uvC3IBgv1lr7Tx_sjpxj_sZ5q3O7I51myyzrE4E-lQdIt-238cU7wVtRbLn0-blk1U5jvlCTDfIXFDplAhKqS-PenCKVMmqcxQPbI7TUd9zE5e1V1E3qppPwKPhTHQuAdoQaTdHmWQ%2F" width="348" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now test this by tweeting a URL from your blog. If its is working you should see a tweet card with an image from your post, title and blog URL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmFl6pyPKLJjnCt0bidD66OZLq7NDk3W4q77LI1bHjUE5HnLTHHr86zpuPQ9LU1bI9qSlziNtczYGmzVIv_WYtjPxORcYlPVPnRv8VmXDJf8iTx6SsIBlWPGEDEBKpXB2FJWCdFhHACSc/" 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%2Fblogger.googleusercontent.com%2Fimg%2Fb%2FR29vZ2xl%2FAVvXsEgmFl6pyPKLJjnCt0bidD66OZLq7NDk3W4q77LI1bHjUE5HnLTHHr86zpuPQ9LU1bI9qSlziNtczYGmzVIv_WYtjPxORcYlPVPnRv8VmXDJf8iTx6SsIBlWPGEDEBKpXB2FJWCdFhHACSc%2F" width="1210" height="872"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>seo</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
