<?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>Forem: Jayson Rawlins</title>
    <description>The latest articles on Forem by Jayson Rawlins (@jjrawlins).</description>
    <link>https://forem.com/jjrawlins</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1146434%2Fc281de15-bf89-44b2-bc87-c6b323d6e3f4.jpg</url>
      <title>Forem: Jayson Rawlins</title>
      <link>https://forem.com/jjrawlins</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jjrawlins"/>
    <language>en</language>
    <item>
      <title>Use Fork Git Client to Remove Passwords from Git History</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Mon, 24 Nov 2025 10:52:25 +0000</pubDate>
      <link>https://forem.com/jjrawlins/use-fork-git-client-to-remove-passwords-from-git-history-3in</link>
      <guid>https://forem.com/jjrawlins/use-fork-git-client-to-remove-passwords-from-git-history-3in</guid>
      <description>&lt;h2&gt;
  
  
  What is Fork
&lt;/h2&gt;

&lt;p&gt;Fork is a git client that runs your git commands for you inside of an interface.  Similar to other products like GitHub Desktop abd GitKraken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I like Fork
&lt;/h2&gt;

&lt;p&gt;Fork UI provides a great deal of flexibility when setting up custom commands.  The interface is decent and provides quick and easy GUI for all your Git needs.&lt;/p&gt;

&lt;p&gt;However, being able to setup your client to run various commands on the repo is very handy.&lt;/p&gt;

&lt;p&gt;Currently I have my JetBrain's products plus the ability to scan for secrets using nosey parker.  All very very handy.  I even use AICommit2 from time to time with a click of a button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meat and Potatoes
&lt;/h2&gt;

&lt;p&gt;Using fork to delete a file out of git history.&lt;/p&gt;

&lt;p&gt;1.) Create a Custom Command&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%2Fcn25ivd5skyiehlici4r.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%2Fcn25ivd5skyiehlici4r.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2.) Call the custom command 'Remove Selected File from History'&lt;/p&gt;

&lt;p&gt;Target needs to be &lt;code&gt;File visible in file context menu&lt;/code&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%2Fct40hocgd22rdv4r78cy.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%2Fct40hocgd22rdv4r78cy.png" alt="Git Security" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3.) Select Bash Command&lt;/p&gt;

&lt;p&gt;Add the following Script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git filter-branch --force --index-filter "git rm --cached --ignore-unmatch '${file}'" --prune-empty --tag-name-filter cat -- --all &amp;amp;&amp;amp; git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d &amp;amp;&amp;amp; git reflog expire --expire=now --all &amp;amp;&amp;amp; git gc --prune=now --aggressive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F7hwhmudg2zfdxh5wtky7.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%2F7hwhmudg2zfdxh5wtky7.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can simply right click on the offending file and remove its entire history (remember to ignore the file so it doesn't get committed again).&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%2Fr42rhppw4z7hfb5fifgg.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%2Fr42rhppw4z7hfb5fifgg.png" alt=" " width="696" height="1178"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>fork</category>
      <category>development</category>
    </item>
    <item>
      <title>Ever Heard of Agentic Memory?</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Mon, 23 Jun 2025 12:05:49 +0000</pubDate>
      <link>https://forem.com/jjrawlins/ever-heard-of-agentic-memory-2jnl</link>
      <guid>https://forem.com/jjrawlins/ever-heard-of-agentic-memory-2jnl</guid>
      <description>&lt;p&gt;Agentic memory is an interesting concept designed to address a specific challenge: the cumbersome ways we currently save preferences, whether through cursor files, Windsurf files, Claude.MD, or other IDEs and AI agents.&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%2Fqqyhzvjr8t7akw0yqf15.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%2Fqqyhzvjr8t7akw0yqf15.png" width="512" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over time, this becomes unwieldy, as you constantly track preferences and re-teach your agent problems it has already solved in different contexts.&lt;/p&gt;

&lt;p&gt;While a flat file could repeatedly instruct the agent on how to solve problems, you would then need to meticulously track the location of these solutions, much like managing a scattered collection of notes across various Git repositories.&lt;/p&gt;

&lt;p&gt;How about keeping these preferences in a database?&lt;/p&gt;

&lt;p&gt;Thus, agentic memory is the idea of remembering your preferences in a graph database.&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%2Fks5qpn2cta2cf3mn0no6.gif" 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%2Fks5qpn2cta2cf3mn0no6.gif" width="560" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With each request, your agent will call an MCP server (model context protocol) and look up your preferences already saved in your database. If they don’t exist, then you can have the agent save it from the current projects results.   &lt;/p&gt;

&lt;p&gt;This greatly speeds up the life cycle when you are vibe coding or asking for help with projects but now you don’t have to keep reminding the agent of your preferences.&lt;/p&gt;

&lt;p&gt;My guess is that over time, use of agentic memory will be standard practice. Just google ‘agentic memory’ and you will find copious amounts of resources and products.   &lt;/p&gt;

&lt;p&gt;Here are some examples that I shamelessly took from &lt;a href="https://www.graphlit.com/blog/survey-of-ai-agent-memory-frameworks" rel="noopener noreferrer"&gt;https://www.graphlit.com/blog/survey-of-ai-agent-memory-frameworks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Letta: &lt;a href="https://docs.letta.com/" rel="noopener noreferrer"&gt;https://docs.letta.com/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Mem0: &lt;a href="https://docs.mem0.ai/" rel="noopener noreferrer"&gt;https://docs.mem0.ai/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
CrewAI: &lt;a href="https://docs.crewai.com/concepts/memory" rel="noopener noreferrer"&gt;https://docs.crewai.com/concepts/memory&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Zep: &lt;a href="https://help.getzep.com/" rel="noopener noreferrer"&gt;https://help.getzep.com/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Memary: &lt;a href="https://kingjulio8238.github.io/memarydocs/concepts/" rel="noopener noreferrer"&gt;https://kingjulio8238.github.io/memarydocs/concepts/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Cognee: &lt;a href="https://www.cognee.ai/blog/fundamentals/llm-memory-cognitive-architectures-with-ai" rel="noopener noreferrer"&gt;https://www.cognee.ai/blog/fundamentals/llm-memory-cognitive-architectures-with-ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>SlackBot Timeouts Getting You Down?</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Wed, 16 Apr 2025 11:53:20 +0000</pubDate>
      <link>https://forem.com/jjrawlins/slackbot-timeouts-getting-you-down-2lic</link>
      <guid>https://forem.com/jjrawlins/slackbot-timeouts-getting-you-down-2lic</guid>
      <description>&lt;h2&gt;
  
  
  Problem with SlackBots and Lambdas:
&lt;/h2&gt;

&lt;p&gt;Slack APIs have a 3-second timeout, so if the Lambda doesn’t respond, you’ll receive a timeout message in the Slack channel before the response is ever issued.&lt;/p&gt;

&lt;p&gt;Here are some reasons for these timeouts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Attempting to process too much information within the 3-second window.&lt;/li&gt;
&lt;li&gt;Cold Starts. Lambdas that haven’t been used in a way can suffer from taking an extra second or two to process the incoming message.&lt;/li&gt;
&lt;li&gt;Database retrieval. Pulling data and processing can sometimes eat up what remains from that 3-second window.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, by using an API gateway, you now have plenty of time to process the data because Slack will get the response immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution Architecture
&lt;/h2&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%2Fri3naij4l17znzxhwyev.gif" 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%2Fri3naij4l17znzxhwyev.gif" alt=" " width="602" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By first going through the API Gateway, you can respond immediately to Slack while sending a copy to SQS, triggering the Lambda with the SQS message. This gives your lambda plenty of time to process data, look up information, make requests, or do whatever it needs to do to provide a response back to the originating channel or perhaps another Slack channel.   &lt;/p&gt;

&lt;p&gt;No timeouts, just a nice workflow that you could wire in any logic.&lt;/p&gt;

</description>
      <category>slackapi</category>
      <category>slackbots</category>
    </item>
    <item>
      <title>Secure Your AWS Resources with Twingate VPN</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Wed, 26 Mar 2025 21:33:16 +0000</pubDate>
      <link>https://forem.com/jjrawlins/secure-your-aws-resources-with-twingate-vpn-4em6</link>
      <guid>https://forem.com/jjrawlins/secure-your-aws-resources-with-twingate-vpn-4em6</guid>
      <description>&lt;h2&gt;
  
  
  Twingate Architecture:
&lt;/h2&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%2Fpqcv1zrd2mcclxwp7hu1.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%2Fpqcv1zrd2mcclxwp7hu1.png" alt="Twingate VPN Architecture in AWS" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits:
&lt;/h2&gt;

&lt;p&gt;1.) Unlike OpenVPN, which requires exposing your VPN EC2 asset to a public subnet, Twingate connectors do not require an inbound security group.&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%2Fdxozi875lhc1jva9shuu.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%2Fdxozi875lhc1jva9shuu.png" alt="Security Group Setup" width="800" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Another benefit is that the network is controlled by groups, so you don’t need separate logins for each account. Log in once, and if you have the correct resource permissions set up, you can access everything you need.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deployment:
&lt;/h2&gt;

&lt;p&gt;There are several options for deploying a connector. The documentation is really good. You can deploy via Kubernetes, CloudFormation, or Terraform.&lt;/p&gt;

&lt;p&gt;We rolled our own CDK stack that deploys the AMI, AWS Secret, and maintenance schedule with an SSM document to perform the updates. This allowed us to deploy it once and basically forget about it as it updates itself. Since we deploy it in two AZs, it rarely ever has an outage.&lt;/p&gt;

&lt;p&gt;For more information, I highly recommend their documentation -&amp;gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twingate.com/docs/" rel="noopener noreferrer"&gt;https://www.twingate.com/docs/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>networking</category>
      <category>twingate</category>
      <category>vpn</category>
    </item>
    <item>
      <title>ECS CloudFormation Taking Forever – Just for a Failed Deployment</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Thu, 20 Mar 2025 16:16:54 +0000</pubDate>
      <link>https://forem.com/jjrawlins/ecs-cloudformation-taking-forever-just-for-a-failed-deployment-3636</link>
      <guid>https://forem.com/jjrawlins/ecs-cloudformation-taking-forever-just-for-a-failed-deployment-3636</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Sometimes, when you deploy an AWS ECS service using CDK or a CloudFormation stack, you end up in a strange situation where the deployment seems to go on forever. The tasks aren’t deployed, the tasks are failing health checks, and ECS just keeps starting new tasks.&lt;/p&gt;

&lt;p&gt;Sometimes, you can see even the old tasks aren’t passing health checks. That’s a guarantee that your poor service is going to take forever to fail, according to CloudFormation.&lt;/p&gt;

&lt;p&gt;You’re waiting and waiting and waiting. You already know how to fix it and are ready to move on; however, CloudFormation just keeps trying in vain. This can be a really frustrating experience.&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/http%3A%2F%2F18.117.137.119%2Fwp-content%2Fuploads%2F2025%2F03%2Fimage-1.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/http%3A%2F%2F18.117.137.119%2Fwp-content%2Fuploads%2F2025%2F03%2Fimage-1.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Trick CloudFormation Into ‘Thinking’ It Succeeded
&lt;/h2&gt;

&lt;p&gt;So, a basic way to trick CloudFormation into thinking everything has been deployed successfully is to redeploy the service in the AWS Console.&lt;/p&gt;

&lt;p&gt;Yes, that’s right. You can redeploy the service in the AWS Console, but this time, you are going to set the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DesiredCount: 0&lt;/li&gt;
&lt;li&gt;MinCount: 0&lt;/li&gt;
&lt;li&gt;MaxCount: 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;REMEMBER:&lt;/strong&gt;  You are not changing anything else in the service; you are just changing the desired, min, and max count to 0. Also, you don’t need to check the box to force a redeployment.&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/http%3A%2F%2F18.117.137.119%2Fwp-content%2Fuploads%2F2025%2F03%2Fimage-2-1024x688.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/http%3A%2F%2F18.117.137.119%2Fwp-content%2Fuploads%2F2025%2F03%2Fimage-2-1024x688.png" alt="ECS Scaling Group" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After all the tasks have been stopped, CloudFormation will  &lt;strong&gt;think&lt;/strong&gt;  that everything has been deployed successfully.&lt;/p&gt;

&lt;p&gt;This will allow you to continue debugging your service without waiting hours for CloudFormation to time out or for the number of retries to finally be exhausted.&lt;/p&gt;

&lt;p&gt;This trick has saved me much time and frustration over the years.&lt;/p&gt;

</description>
      <category>awsecs</category>
      <category>aws</category>
      <category>devops</category>
      <category>ecs</category>
    </item>
    <item>
      <title>Site to Site VPN</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Thu, 20 Mar 2025 16:09:33 +0000</pubDate>
      <link>https://forem.com/jjrawlins/site-to-site-vpn-4fo4</link>
      <guid>https://forem.com/jjrawlins/site-to-site-vpn-4fo4</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Site-to-site VPN provides a secure tunnel between two networks. Unlike, say, VPN peering, where you have a connection between one AWS VPC and another AWS VPC, site-to-site VPN allows you to connect two networks that are not even in AWS. You could connect an on-premise network to the AWS network, or you could connect two different cloud providers together, like AWS and Azure.  &lt;/p&gt;

&lt;p&gt;Here is an example of a Site-to-Site VPN between AWS and Azure&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=G8hwCso8JSs&amp;amp;t=3s" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=G8hwCso8JSs&amp;amp;t=3s&lt;/a&gt;&lt;br&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%2Fiep47s6yqkp5aixhih14.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%2Fiep47s6yqkp5aixhih14.png" alt="https://www.youtube.com/watch?v=G8hwCso8JSs&amp;amp;t=3s" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a YouTube video that shows how to set up a Site-to-Site VPN between AWS and Azure.&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Play&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Site-to-Site VPN AWS to Azure&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is a step-by-step guide to setting up a Site-to-Site VPN between AWS and Azure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjrawlins/youtube/blob/main/entra-id-site-2-site-vpn/instructions.md" rel="noopener noreferrer"&gt;https://github.com/jjrawlins/youtube/blob/main/entra-id-site-2-site-vpn/instructions.md&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Site-to-Site VPN is a great way to connect two networks that are not on the same cloud provider. It is also a great way to connect on-premise networks to the cloud.&lt;/p&gt;

&lt;p&gt;Stay tuned for more tutorials and examples of building durable, secure cloud infrastructure!&lt;/p&gt;

</description>
      <category>networking</category>
      <category>aws</category>
      <category>azure</category>
    </item>
    <item>
      <title>How to Create a Custom Resource with AWS CDK</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Thu, 20 Mar 2025 01:54:22 +0000</pubDate>
      <link>https://forem.com/jjrawlins/how-to-create-a-custom-resource-with-aws-cdk-4aj1</link>
      <guid>https://forem.com/jjrawlins/how-to-create-a-custom-resource-with-aws-cdk-4aj1</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;The AWS Cloud Development Kit (CDK) allows you to define cloud infrastructure using familiar programming languages. While CDK provides a wide range of constructs, there are scenarios where you might need to create custom resources to extend its capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are Custom Resources?
&lt;/h3&gt;

&lt;p&gt;Custom Resources in AWS CDK enable you to write custom provisioning logic in AWS Lambda or other services. This allows you to perform operations that are not natively supported by CDK constructs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Custom Resource
&lt;/h3&gt;

&lt;p&gt;To create a custom resource, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize the CDK Project using Projen&lt;/li&gt;
&lt;li&gt;Define the Lambda Function: This function will contain the custom logic using Projen&lt;/li&gt;
&lt;li&gt;Create the Custom Resource: Use the CustomResource construct and link it to your Lambda function.&lt;/li&gt;
&lt;li&gt;Use the Custom Resource in Your Stack: Integrate the custom resource into your CDK stack as needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Here’s a simple example of creating a custom resource in AWS CDK:&lt;/p&gt;

&lt;h5&gt;
  
  
  Step 1: Initialize a new Projen Project
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx projen new awscdk-app-ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s a simple example of creating a custom resource in AWS CDK:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjrawlins/cdk-examples/tree/main/projen-typescript/cdk-custom-resource" rel="noopener noreferrer"&gt;https://github.com/jjrawlins/cdk-examples/tree/main/projen-typescript/cdk-custom-resource&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside the src directory, create a new directory called stacks. Then, create a new file called CustomResourceExampleStack.ts inside the src/ stacks directory.&lt;/p&gt;

&lt;h4&gt;
  
  
  CustomResourceExampleStack.ts
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CustomResource, Duration, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { ExampleCustomResourceLambdaFunction } from '../lambdas/ExampleCustomResourceLambda-function';

interface CustomResourceExampleStackProps extends StackProps {

}

export class CustomResourceExampleStack extends Stack {
  constructor(scope: Construct, id: string, props: CustomResourceExampleStackProps) {
    super(scope, id, props);

    const customResourceLambda = new ExampleCustomResourceLambdaFunction(this, 'CustomResourceLambda', {
      description: 'Example of a custom resource lambda',
      memorySize: 128,
      timeout: Duration.seconds(30),
    });

    const stackName = Stack.of(this).stackName;
    new CustomResource(this, 'CustomResource', {
      serviceToken: provider.serviceToken,
      properties: {
        PhysicalResourceId: \${stackName}-CustomResourceResource-version,
        MyCustomProperty: 'MyCustomValue',
      },
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Define the Lambda Function
&lt;/h3&gt;

&lt;p&gt;Create a new directory called lambdas inside the src/ directory. Inside the lambdas directory, create a new file called ExampleCustomResource.lambda.ts. This file will contain the logic for your custom resource.&lt;/p&gt;

&lt;p&gt;You can always add more logic to this file as needed. Mostly serves as a starting point.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; import {
    CdkCustomResourceResponse,
    CloudFormationCustomResourceCreateEvent,
    CloudFormationCustomResourceDeleteEvent,
    CloudFormationCustomResourceEvent,
    CloudFormationCustomResourceUpdateEvent,
    Context,
} from 'aws-lambda';

    const region = process.env.AWS_REGION;

    export const handler = async (
    event: CloudFormationCustomResourceEvent,
    context: Context,
    ): Promise&amp;lt;CdkCustomResourceResponse&amp;gt; =&amp;gt; {
    console.log('Lambda is invoked with:' + JSON.stringify(event));
    console.log('Context is invoked with:' + JSON.stringify(context));
    console.log('Lambda is invoked with:' + JSON.stringify(event));
    console.log('Region: ' + region);
    const physicalResourceId = event.ResourceProperties.PhysicalResourceId;

    let response: CdkCustomResourceResponse = {
    Status: 'SUCCESS',
    Reason: 'See the details in CloudWatch Log Stream: ' + context.logStreamName,
    PhysicalResourceId: physicalResourceId,
    StackId: event.StackId,
    RequestId: event.RequestId,
    LogicalResourceId: event.LogicalResourceId,
};

    switch (event.RequestType) {
    case 'Create':
    response = await onCreate(response, event, context);
    break;
    case 'Delete':
    response = await onDelete(response, event, context);
    break;
    case 'Update':
    response = await onUpdate(response, event, context);
    break;
    default:
    throw new Error('Unknown Request Type of CloudFormation');
}
    console.log('Return value:', JSON.stringify(response));
    return response;
};

    /**
    * Executes the create event for a CloudFormation custom resource.
    * @param {CdkCustomResourceResponse} response - The custom resource response object.
    * @param {CloudFormationCustomResourceCreateEvent} event - The create event object.
    * @param {Context} context - The AWS Lambda context object.
    * @return {Promise&amp;lt;CdkCustomResourceResponse&amp;gt;} - A promise that resolves to the custom resource response object.
    */
    export async function onCreate(
    response: CdkCustomResourceResponse,
    event: CloudFormationCustomResourceCreateEvent,
    context: Context): Promise&amp;lt;CdkCustomResourceResponse&amp;gt; {
    try {
    console.log('We are in the Create Event');
    console.log('Event is invoked with:' + JSON.stringify(event));
    console.log('Context is invoked with:' + JSON.stringify(context));
} catch (error) {
    if (error instanceof Error) {
    response.Reason = error.message;
}
    response.Status = 'FAILED';
    response.Data = { Result: error };
    return response;
}
    return response;
}

    /**
    * Handles delete event for a cloud formation custom resource.
    *
    * @param {CdkCustomResourceResponse} response - The custom resource response object.
    * @param {CloudFormationCustomResourceDeleteEvent} event - The delete event object.
    * @param {Context} context - The AWS lambda context object.
    * @returns {Promise&amp;lt;CdkCustomResourceResponse&amp;gt;} - The updated custom resource response object.
    */
    export async function onDelete(
    response: CdkCustomResourceResponse,
    event: CloudFormationCustomResourceDeleteEvent,
    context: Context): Promise&amp;lt;CdkCustomResourceResponse&amp;gt; {
    try {
    console.log('We are in the Delete Event');
    console.log('Context is invoked with:' + JSON.stringify(context));
    console.log('Event is invoked with:' + JSON.stringify(event));
    response.Status = 'SUCCESS';
} catch (error) {
    if (error instanceof Error) {
    response.Reason = error.message;
}
    response.Status = 'FAILED';
    response.Data = { Result: error };
    return response;
}
    return response;
}

    /**
    * Executes the onUpdate logic for a CloudFormation custom resource.
    *
    * @param {CdkCustomResourceResponse} response - The response object for the custom resource.
    * @param {CloudFormationCustomResourceUpdateEvent} event - The update event object from CloudFormation.
    * @param {Context} context - The execution context object.
    * @returns {Promise&amp;lt;CdkCustomResourceResponse&amp;gt;} A promise that resolves to the updated response object.
    */
    export async function onUpdate(
    response: CdkCustomResourceResponse,
    event: CloudFormationCustomResourceUpdateEvent,
    context: Context): Promise&amp;lt;CdkCustomResourceResponse&amp;gt; {
    try {
    console.log('Resource properties: ' + JSON.stringify(event.ResourceProperties));
    console.log('Event is invoked with:' + JSON.stringify(event));
    console.log('Context is invoked with:' + JSON.stringify(context));
} catch (error) {
    if (error instanceof Error) {
    response.Reason = error.message;
}
    response.Status = 'FAILED';
    response.Data = { Result: error };
    return response;
}
    return response;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Generate New Lambda Function
&lt;/h3&gt;

&lt;p&gt;One of the neat things about using projen to create your lambda function is that it will autogenerate the lambda function.&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Play&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ProjenLambdaGeneration&lt;/em&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx projen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;main.ts&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   import { App } from 'aws-cdk-lib';
    import { CustomResourceExampleStack } from './stacks/CustomResourceExampleStack';

    // for development, use account/region from cdk cli
    const devEnv = {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEFAULT_REGION,
};

    const app = new App();

    new CustomResourceExampleStack(app, 'cdk-custom-resource-dev', { env: devEnv });

    app.synth();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Deploy Your Custom Resource
&lt;/h3&gt;

&lt;p&gt;Deploy the custom resource using the following commands:&lt;/p&gt;

&lt;p&gt;NOTE: You will have to be authenticated in an AWS Profile to work.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn cdk deploy cdk-custom-resource-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;span&gt;Play&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Deploy CDK Custom Resource&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;CDK custom resources are a powerful way to extend the functionality of AWS CDK. They allow you to perform operations that are not directly supported by existing CDK constructs, giving you greater flexibility in defining your infrastructure.&lt;/p&gt;

&lt;p&gt;Stay tuned for more tutorials and examples on AWS CDK and other cloud technologies!&lt;/p&gt;

</description>
      <category>cdk</category>
      <category>ecs</category>
    </item>
    <item>
      <title>ECS CloudFormation Taking Forever - Just for a Failed Deployment</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Thu, 13 Mar 2025 20:57:34 +0000</pubDate>
      <link>https://forem.com/aws-builders/ecs-cloudformation-taking-forever-just-for-a-failed-deployment-41k7</link>
      <guid>https://forem.com/aws-builders/ecs-cloudformation-taking-forever-just-for-a-failed-deployment-41k7</guid>
      <description>&lt;p&gt;Introduction&lt;br&gt;
Sometimes times when you are deploying an AWS ECS service using CDK or a CloudFormation stack, you end up in a strange situation where the deployment seems to go on forever. The tasks aren't deployed, the tasks are failing health checks, and ECS just keeps starting new tasks.&lt;/p&gt;

&lt;p&gt;Sometimes, you can see even the old tasks aren't passing health checks. That's a guarantee that your poor service is going to take forever to fail, according to CloudFormation.&lt;/p&gt;

&lt;p&gt;You're waiting and waiting and waiting. You already know how to fix it and are ready to move on; however, CloudFormation just keeps trying in vain. This can be a really frustrating experience.&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%2F6e5356u76kgd3wr8abo3.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%2F6e5356u76kgd3wr8abo3.png" alt="Person staring at their computer screen" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How to Trick CloudFormation Into 'Thinking' It Succeeded&lt;br&gt;
So, a basic way to trick CloudFormation into thinking that everything has been deployed successfully is to simply redeploy the service in the AWS Console.&lt;/p&gt;

&lt;p&gt;Yeap, that's right. You can redeploy the service in the AWS Console, but this time, you are going to set the following parameters:&lt;/p&gt;

&lt;p&gt;DesiredCount: 0&lt;br&gt;
MinCount: 0&lt;br&gt;
MaxCount: 0&lt;/p&gt;

&lt;p&gt;REMEMBER: You are not changing anything else in the service; you are just changing the desired, min, and max count to 0. Also, you don't need to check the box to force a redeployment.&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%2F2uyzx019l6yuoqtzjg60.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%2F2uyzx019l6yuoqtzjg60.png" alt="ECS AWS console settings" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After all the tasks have been stopped, cloudformation will think that everything has been deployed successfully.&lt;/p&gt;

&lt;p&gt;This will allow you to continue debugging your service without waiting hours for cloudformation to timeout or for the number of retries to finally have been exhausted.&lt;/p&gt;

&lt;p&gt;This trick has saved me a lot of time and frustration over the years.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Tired of Evernote? Try Obsidian!</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Mon, 06 Nov 2023 02:56:13 +0000</pubDate>
      <link>https://forem.com/jjrawlins/tired-of-evernote-try-obsidian-ghj</link>
      <guid>https://forem.com/jjrawlins/tired-of-evernote-try-obsidian-ghj</guid>
      <description>&lt;h3&gt;
  
  
  Introduction:
&lt;/h3&gt;

&lt;p&gt;Back in my college days, Evernote was my go-to digital notebook for both academic and professional use. Its robust features and seamless browser integration significantly boosted my productivity. Despite its premium price tag, the value it delivered made it a justifiable expense. The convenience and efficiency it brought to my daily workflow were undeniable, turning the routine task of note-taking into a dynamic and integral part of my success.&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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fe268bf96-e48e-4aba-8e7b-af44c5b3e200.webp" 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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fe268bf96-e48e-4aba-8e7b-af44c5b3e200.webp" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tactile tradition of pen and paper soon gave way to the digital convenience of Evernote’s Plugin. This modern method became a staple of my daily routine, faithfully serving me throughout the extended journey of earning my second Bachelor’s degree at the University of Central Florida. Over those years, my reliance on the Evernote Plugin transformed the way I captured information and organized my academic life.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cutting Costs
&lt;/h3&gt;

&lt;p&gt;After getting that shiny diploma from UCF, my wallet was like, ‘No more fancy stuff!’ So, I gave it a break and hopped onto the freebie train with OneNote! &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%2Fszrhl617fwlhfwlrikzj.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%2Fszrhl617fwlhfwlrikzj.png" alt="🎓" width="72" height="72"&gt;&lt;/a&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%2Ftnub89eu2ktvfz3aotut.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%2Ftnub89eu2ktvfz3aotut.png" alt="🚂" width="72" height="72"&gt;&lt;/a&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%2F39tqfvmiek8m3xjmsge5.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%2F39tqfvmiek8m3xjmsge5.png" alt="💡" width="72" height="72"&gt;&lt;/a&gt;”&lt;/p&gt;

&lt;p&gt;Using OneNote was fine for a while. I already had Office 365. However, in the world of note-taking, Obsidian’s integration of markdown makes it an optimal choice for those handling code. Markdown offers consistent and easy-to-add code assertions, streamlining the note-taking process. While OneNote might require external plugins like &lt;a href="https://github.com/elvirbrk/NoteHighlight2016" rel="noopener noreferrer"&gt;NoteHighlight2016&lt;/a&gt; to achieve similar functionality, Evernote, though plugin-free, can sometimes present challenges with buggy code formatting. In contrast, Obsidian provides a seamless and reliable experience straight from the outset. Dive into the &lt;a href="https://obsidian.md" rel="noopener noreferrer"&gt;Obsidian platform&lt;/a&gt; and witness the precision and efficiency markdown can bring to your notes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;So, there are two complaints that I have with Obsidian.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Videos&lt;/strong&gt;. It is not practical or easy to embed YouTube videos. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes they work great but other times, its kinda annoying in that you end up with blank videos. Here is an example:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/mPaGi1Phc5A?si=M9x50CP3zk5oKi0O" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/giroZqjTJqE?si=pOjMZtf4S6rerAYW" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-1.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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-1.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This what it should look like:&lt;/p&gt;

&lt;p&gt;The reason, as I understand it, is that embedded YouTube videos sometimes have settings that make them not work locally. Obsidian uses a local file system rather than a hosted website like OneNote, Evernote, or Google Keep.&lt;/p&gt;

&lt;p&gt;However, I recommend using the &lt;strong&gt;‘thumbnails’&lt;/strong&gt; community plugin.&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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-3.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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-3.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This isn’t quite as nice as embedding, but it works well. So, for the above two videos, I can use the following markdown:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
vid&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=mPaGi1Phc5A" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=mPaGi1Phc5A&lt;/a&gt;&lt;br&gt;
vid&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=giroZqjTJqE" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=giroZqjTJqE&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-4.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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-4.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;File-explorer&lt;/strong&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, only markdown files are displayed. To add files like animated GIFs or, in my case, I wanted to link to PDFs stored within my notes. However, you can turn this feature on:&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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-2-1024x841.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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-2-1024x841.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Storage Options:
&lt;/h3&gt;

&lt;p&gt;If you are OK with keeping your notes on your cloud, it can be pretty much limitless. If you need your notes on the go, remember you will pay an extra premium. At the time of writing, it was $8.00 US/month billed yearly and $10.00 US/month billed monthly. It’s slightly less expensive than Evernote but definitely a premium compared to OneNote or Google Keep, which are both free.&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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-6.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%2Fjaysonrawlins.com%2Fwp-content%2Fuploads%2F2023%2F11%2Fimage-6.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion:
&lt;/h3&gt;

&lt;p&gt;While Obsidian may come with its share of quirks, its speed and practicality cannot be overstated when it comes to organizing notes. Opting for the cloud sync service proved to be a wise decision, especially during my vacation. The ability to access my notes on my phone, effortlessly embed PDFs, and manage my itinerary was nothing short of remarkable. Even in moments when internet connectivity was a distant dream, Obsidian stood out as an indispensable travel companion, keeping my plans well-ordered and within reach. It’s clear that despite any minor inconveniences, Obsidian offers a seamless, user-friendly experience for anyone looking to keep their thoughts and plans neatly aligned.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://jaysonrawlins.com/tired-of-evernote-try-obsidian/" rel="noopener noreferrer"&gt;Tired of Evernote? Try Obsidian!&lt;/a&gt; appeared first on &lt;a href="https://jaysonrawlins.com" rel="noopener noreferrer"&gt;Jayson Rawlins&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>uncategorized</category>
      <category>obsidian</category>
      <category>productivity</category>
    </item>
    <item>
      <title>ECS Copilot with SQS Autoscaling</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Fri, 27 Oct 2023 18:46:21 +0000</pubDate>
      <link>https://forem.com/jjrawlins/ecs-copilot-with-sqs-autoscaling-56l0</link>
      <guid>https://forem.com/jjrawlins/ecs-copilot-with-sqs-autoscaling-56l0</guid>
      <description>&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ECS Copilot:&lt;/strong&gt; ECS Copilot that has been overridden to expose CDK. See &lt;a href="https://aws.github.io/copilot-cli/docs/commands/svc-override/" rel="noopener noreferrer"&gt;svc override — AWS Copilot CLI&lt;/a&gt;. Probably could use the same principles with regular CDK as well but this particular example assumes we are using ECS Copilot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Typescript&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CDK v2&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NPM&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CDK IAM Floyd (Library for helping manage AWS IAM)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install cdk-iam-floyd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;tranformService():&lt;/strong&gt; This is the function that starts of with &lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const service = this.template.getResource("Service") as ecs.CfnService;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notes:
&lt;/h3&gt;

&lt;p&gt;As mentioned before, this could be used for any CDK project. However, for this demonstration ECS Copilot is assumed which will include some commands that simply would not be necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lets get started:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transformService() {
  let minCapacity = 2;
  let maxCapacity = 48;
  let queueName = "your_queue_name"

  ## With regular CDK, you will have the Service Object directly.
  const service = this.template.getResource("Service") as ecs.CfnService;
  const clusterName = service.cluster;
  const serviceName = service.attrName;

  const scalingRole = new iam.Role(this, 'ServiceScalingRole', {
      assumedBy: new iam.ServicePrincipal('ecs.application-autoscaling.amazonaws.com'),
      inlinePolicies: {
          'ScalingRoleInlinePolicy': new PolicyDocument({
              statements: [
                  new floyd.ApplicationAutoscaling().allow().onAllResources().allActions(),
                  new floyd.Ecs().allow().onAllResources()
                      .toDescribeServices()
                      .toUpdateService(),
                  new floyd.Cloudwatch().allow().onAllResources()
                      .toDescribeAlarms()
                      .toPutMetricAlarm()
                      .toDeleteAlarms()
                      .toDescribeAlarmHistory()
                      .toDescribeAlarmsForMetric()
                      .toGetMetricStatistics()
                      .toListMetrics()
                      .toDisableAlarmActions()
                      .toEnableAlarmActions(),
                  new floyd.Iam().allow().onAllResources()
                      .toCreateServiceLinkedRole(),
                  new floyd.Sns().allow().onAllResources()
                      .toCreateTopic()
                      .toSubscribe(),
                  new floyd.Sns({
                      actions: [
                          "sns:Get*",
                          "sns:List*"
                      ]
                  }).allow().onAllResources()
              ]
          })
      }
  });

  // First, get the ScalableTarget associated with the service
  const resourceId = `service/${clusterName}/${serviceName}`;

  const scalableTarget = new appscaling.CfnScalableTarget(this, 'ServiceScalableTarget', {
      maxCapacity: maxCapacity,
      minCapacity: minCapacity,
      resourceId: resourceId,
      roleArn: scalingRole.roleArn,
      scalableDimension: 'ecs:service:DesiredCount',
      serviceNamespace: 'ecs',
  });

 // This and the previous are only necessary because of ECS Copilot.
 // Could just declare the ScalableTarget directly with CDK.
 const cdkScalableTarget = appscaling.ScalableTarget.fromScalableTargetId(
      this,
      'CdkServiceScalableTarget',
      scalableTarget.ref,
  )

 const metric = new cloudwatch.Metric({
    namespace: 'AWS/SQS',
    metricName: 'ApproximateNumberOfMessagesVisible',
    dimensionsMap: {
        QueueName: queueName,
    },
    statistic: 'Average',
});

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

&lt;/div&gt;



</description>
      <category>uncategorized</category>
      <category>aws</category>
      <category>ecscopilot</category>
      <category>typescript</category>
    </item>
    <item>
      <title>How to build a site using SST, NextJS and a NextJS theme</title>
      <dc:creator>Jayson Rawlins</dc:creator>
      <pubDate>Fri, 27 Oct 2023 17:38:02 +0000</pubDate>
      <link>https://forem.com/jjrawlins/how-to-build-a-site-using-sst-nextjs-and-a-nextjs-theme-48kp</link>
      <guid>https://forem.com/jjrawlins/how-to-build-a-site-using-sst-nextjs-and-a-nextjs-theme-48kp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is SST?
&lt;/h3&gt;

&lt;p&gt;SST is a framework for building serverless. With SST you can build modern full-stack applications on AWS.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy Next.js, Svelte, or Astro to AWS.&lt;/li&gt;
&lt;li&gt;Add any backend feature.&lt;/li&gt;
&lt;li&gt;Go from idea to IPO!&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What is NextJS?
&lt;/h3&gt;

&lt;p&gt;Next.js is a React framework that enables several features such as server-side rendering and generating static websites.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is TailwindCSS?
&lt;/h3&gt;

&lt;p&gt;A NextJS theme is a way to share functionality across multiple NextJS applications. Themes are a great way to share components, pages, and styles across multiple applications.&lt;/p&gt;

&lt;p&gt;I got this theme from &lt;a href="https://themefisher.com/best-nextjs-templates" rel="noopener noreferrer"&gt;https://themefisher.com/best-nextjs-templates&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Step 1: Download the theme
&lt;/h4&gt;

&lt;p&gt;Go to a theme site like &lt;a href="https://themefisher.com/best-nextjs-templates" rel="noopener noreferrer"&gt;https://themefisher.com/best-nextjs-templates&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Unzip the theme
&lt;/h4&gt;

&lt;p&gt;Place the zipped them into a folder.&lt;/p&gt;

&lt;p&gt;In my case I downloaded it to ~/Dev/bookwork-light-nextjs&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Compile the theme and see how it works.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/Dev/bookwork-light-nextjs
yarn install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fesjsmow6xncnvtjxelqt.gif" 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%2Fesjsmow6xncnvtjxelqt.gif" width="1469" height="868"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h4&gt;
  
  
  Step 4: Create a new SST project
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-sst@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F7apy982ntbcm3wlosm37.gif" 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%2F7apy982ntbcm3wlosm37.gif" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5: Deploy the application
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx sst deploy --stage prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>nextjs</category>
      <category>react</category>
      <category>sst</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
