<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Jose Cerrejon on Medium]]></title>
        <description><![CDATA[Stories by Jose Cerrejon on Medium]]></description>
        <link>https://medium.com/@ulysess?source=rss-f764afd69244------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*aNKFEZflSwIBwlev.jpg</url>
            <title>Stories by Jose Cerrejon on Medium</title>
            <link>https://medium.com/@ulysess?source=rss-f764afd69244------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 15 Apr 2026 02:22:23 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ulysess/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Debugging an AWS Lambda Function in Python Inside a Docker Container Using VS Code]]></title>
            <link>https://medium.com/@ulysess/debugging-an-aws-lambda-function-in-python-inside-a-docker-container-using-vs-code-492adb99cf18?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/492adb99cf18</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[aws-lambda]]></category>
            <category><![CDATA[debug]]></category>
            <category><![CDATA[vscode]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Mon, 02 Jun 2025 16:49:41 GMT</pubDate>
            <atom:updated>2025-06-02T16:49:41.860Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jbu0AKoac7AuXTI0HbHPfw.png" /><figcaption>VSCode helps you debug Lambda functions</figcaption></figure><p>I’ve been working for months on a project that uses <em>AWS Lambda + Python + FastAPI + Docker</em>. I tried to debug a <em>Lambda</em> following several tutorials, AI, <em>Medium</em> articles, and <em>YouTube</em> videos without success. Almost all of them were obsessed with using <em>AWS SAM</em>, which I don’t use at all. So I took advantage of a quiet Sunday afternoon in my dungeon (I mean basement), and finally found a way to make it work. I’ll show you how below and I hope it helps you. 😉</p><h3>Introduction</h3><p>First things first.</p><p>To debug an <em>AWS Lambda</em> function locally with Docker and VSCode, the idea is to run the function inside a <em>Docker</em>container with a <em>Lambda</em>, and then connect the <em>VS Code</em> debugger to a <em>Python</em> process inside the container. What worked for me was importing <em>Mangum + debugpy</em> in the image, and using it to start the <em>FastAPI</em> server.</p><p>Don’t worry, I’ll explain everything step by step.</p><h3>Requirements</h3><ul><li><em>Docker</em> (I use <em>OrbStack</em>).</li><li><em>VS Code</em> with the <em>Python</em> extension installed + <em>Remote — Containers</em>. You probably have both installed.</li></ul><h3>Example Project Structure</h3><p>Before going into details, a possible folder structure for this project could be:</p><pre>.<br>├── lambda.py<br>├── Dockerfile<br>└── .vscode/<br>   └── launch.json</pre><ul><li>lambda.py: contains the <em>FastAPI</em> app and the handler with <em>Mangum</em>.</li><li>Dockerfile: defines the image based on <em>AWS Lambda Python</em>.</li><li>.vscode/launch.json: configuration so that <em>VS Code</em> can “attach” the debugger to the container.</li></ul><p>Let’s continue.</p><h3><a href="https://misapuntesde.com/2025/06/debug_lambda_function_on_python_inside_docker_container_using_vs_code.html#dockerfile-base-image-and-dependencies">Dockerfile: Base Image and Dependencies</a></h3><p>Now let’s create a Dockerfile using the official <em>AWS Lambda for Python</em> image and add the necessary dependencies:</p><pre>FROM public.ecr.aws/lambda/python:3.13<br><br>WORKDIR /app<br><br>RUN pip3 install fastapi mangum debugpy --target &quot;${LAMBDA_TASK_ROOT}&quot;<br><br>COPY lambda.py ${LAMBDA_TASK_ROOT}/lambda.py<br><br>CMD [ &quot;lambda.handler&quot; ]</pre><p>I suppose you know what <em>Lambda_TASK_ROOT</em> is, right? It’s an environment variable that <em>AWS Lambda</em> automatically sets to the directory where the function runs. In this case, we’re installing the dependencies in that directory so they’re available when the function runs.</p><p><a href="https://github.com/Kludex/mangum">Mangum</a>, for those who don’t know, is an adapter that allows you to run <em>ASGI</em> applications (like <em>FastAPI</em>) in an <em>AWS Lambda </em>environment.</p><p>I used <em>pip</em> to keep the example simple, but you can use <em>poetry</em> or <em>pipenv</em> if you prefer. The key is to install the dependencies in the <em>Lambda</em> working directory ${LAMBDA_TASK_ROOT} so they&#39;re available when the function runs.</p><h3>Lambda Function Code (FastAPI + Mangum)</h3><pre>import debugpy  # type: ignore<br>from fastapi import FastAPI  # type: ignore<br>from mangum import Mangum  # type: ignore<br><br>app = FastAPI()<br>debugpy.listen((&quot;0.0.0.0&quot;, 5678))<br>print(&quot;Waiting for debugger to attach...&quot;)<br>debugpy.wait_for_client()<br><br># curl -XPOST &quot;http://localhost:9000/2015-03-31/functions/function/invocations&quot; -d &#39;{&quot;resource&quot;: &quot;/&quot;, &quot;path&quot;: &quot;/&quot;, &quot;httpMethod&quot;: &quot;GET&quot;, &quot;requestContext&quot;: {}, &quot;multiValueQueryStringParameters&quot;: null}&#39;<br>@app.get(&quot;/&quot;)<br>def read_root():<br>    is_testing = True<br>    message = &quot;Hello, world!&quot;<br>    return {<br>        &quot;message&quot;: message,<br>        &quot;is_testing&quot;: is_testing,<br>    }<br><br>handler = Mangum(app)  # Adapter for AWS Lambda</pre><p>This code creates a GET / route and then defines handler = Mangum(app) so that the <em>Lambda</em> correctly invokes the <em>FastAPI</em> application. In <em>VS Code</em> you can set <strong>breakpoints</strong> inside any of these functions/lines once the application is running in debug mode.</p><p>Add a <em>breakpoint</em> for example at the return of the read_root function.</p><h3>VS Code Configuration for Debugging</h3><p>Now let’s configure <em>VS Code</em> to connect to the <em>Docker</em> container and debug the <em>Lambda</em> function. In the .vscode/launch.json file:</p><pre>{<br>    &quot;version&quot;: &quot;0.2.0&quot;,<br>    &quot;configurations&quot;: [<br>        {<br>            &quot;name&quot;: &quot;Python: Attach to remote Lambda&quot;,<br>            &quot;type&quot;: &quot;python&quot;,<br>            &quot;request&quot;: &quot;attach&quot;,<br>            &quot;connect&quot;: {<br>                &quot;host&quot;: &quot;localhost&quot;,<br>                &quot;port&quot;: 5678<br>            },<br>            &quot;pathMappings&quot;: [<br>                {<br>                    &quot;localRoot&quot;: &quot;${workspaceFolder}&quot;,<br>                    &quot;remoteRoot&quot;: &quot;/app&quot;<br>                }<br>            ]<br>        }<br>    ]<br>}</pre><p>Everything should be ready. It should look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*0mysbTAzcJzoqpxM.png" /></figure><h3>Build and Run the Container</h3><p>With a single line, like a pro: 😎</p><pre>docker build -t lambda-debug . &amp;&amp; docker run --rm -p 9000:8080 -p 5678:5678 --name lambda-debug-container lambda-debug</pre><ul><li>- - rm: Removes the container when it stops. Remember that <em>Lambdas</em> only run once and then are destroyed, so this is useful to avoid leaving orphan containers.</li><li>-p 9000:8080: publishes port 8080 of the container to the host on localhost:9000. It listens for requests on /2015-03-31/functions/function/invocations to invoke the function, but this may vary depending on your <em>Lambda</em>configuration. Check the <em>AWS</em> documentation for more details.</li><li>-p 5678:5678: <strong>Important</strong>. This publishes the port where <em>debugpy</em> will listen for the debugger connection.</li></ul><p><strong>Remember</strong>: Every time you make a code change, you’ll need to rebuild the image and restart the container. I need to find a way to automate this, or maybe there’s something so you can make requests without having to restart the container for a <em>Lambda</em>.</p><p>Now <strong>open another terminal</strong> and run the following command to invoke the main function of the <em>Lambda</em>:</p><pre>curl -XPOST &quot;http://localhost:9000/2015-03-31/functions/function/invocations&quot; -d &#39;{&quot;resource&quot;: &quot;/&quot;, &quot;path&quot;: &quot;/&quot;, &quot;httpMethod&quot;: &quot;GET&quot;, &quot;requestContext&quot;: {}, &quot;multiValueQueryStringParameters&quot;: null}&#39;</pre><p>In the first terminal, you should see a message like this:</p><pre>Waiting for debugger to attach...</pre><p>Now, in <em>VS Code</em>, open Run &amp; Debug (Ctrl or cmd+Shift+D) and select the configuration we created earlier: <strong>Python: Attach to remote Lambda</strong>. Then click the green start button or press F5 to start the debugger.</p><p>If everything went well, and you set a breakpoint, you should see in the debug window the variables and the code stopped at the breakpoint. From here you can inspect variables, run commands in the console, and do whatever you want.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pd4bSPEhC_P4xfbw.png" /></figure><p>That’s it. No conclusions or tips. Just… <em>“Enjoy”</em> the debugging process as much as I do! 😉</p><p>Time to clap 👏 &amp; follow me! 👯</p><p><em>On my </em><a href="https://misapuntesde.com"><em>blog</em></a><em>, you can read news/tutorials about Raspberry Pi, Linux, macOS, DevOps, development, and all the things you and I want to learn.<br>Visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>!</em></p><p><em>Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=492adb99cf18" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[My essential Homebrew applications on macOS]]></title>
            <link>https://medium.com/@ulysess/my-essential-homebrew-applications-on-macos-92a4af70dae2?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/92a4af70dae2</guid>
            <category><![CDATA[terminal]]></category>
            <category><![CDATA[tools]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[homebrew]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Sun, 05 Jan 2025 12:49:48 GMT</pubDate>
            <atom:updated>2025-01-05T12:49:48.326Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/872/1*RDgk_0KPokz3AHE6X023JQ.png" /><figcaption>All apps I need using Homebrew</figcaption></figure><p><em>macOS</em> is a versatile operating system, but having the right all the difference for those in the terminal.</p><p>With <a href="https://brew.sh/">Homebrew</a>, managing essential command-line applications becomes effortless. Below, I’ll highlight some of the most indispensable tools in my workflow, each installed and updated via <em>Homebrew</em>, to streamline tasks, enhance productivity, and supercharge the terminal experience. 😊</p><ol><li><strong>Axel: Light UNIX Download Accelerator</strong></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*scGicoLmLXEBMnpjltvvPg.png" /><figcaption><em>axel</em> downloading the latest <em>Raspberry Pi OS image.</em></figcaption></figure><p><strong>Command</strong>: <em>brew install axel</em></p><p><em>axel</em> is a high-performance download accelerator that simplifies file downloads. Utilizing multiple connections to fetch data significantly reduces download times without complicating the command-line experience.</p><p>I use it to download <em>iso</em> images, as seen in the capture above.</p><p><strong>2. Bat: Enhanced cat with Syntax Highlighting</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hx7SkkAA1777ytFV6TTWTw.png" /><figcaption>I prefer bats against cats this time. 😁</figcaption></figure><p><strong>Command</strong>: <em>brew install bat</em></p><p><em>Bat</em> takes the humble cat command to the next level. Featuring syntax highlighting, <em>Git</em> integration, and line numbers… It’s perfect for <em>developers</em> and <em>DevOps</em> who need to read code or configuration files at a glance.</p><p><strong>3. Broot: Intuitive Directory Tree Navigation</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jd3_eCwQGmc65O5-O3n_5A.png" /><figcaption>broot showing a random directory</figcaption></figure><p><strong>Command</strong>: <em>brew install broot</em></p><p><a href="https://dystroy.org/broot/"><em>Broot</em></a> reinvents how you browse directories, offering a visually pleasing tree view combined with fuzzy searching. It’s an indispensable tool for navigating complex file systems quickly and efficiently.</p><p><strong>4. Curl: Web File Transfer Workhorse</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WKZ2jVEFtGsOJbhJbkds4A.png" /><figcaption>I’m using curl for some non-common cases.</figcaption></figure><p><strong>Command</strong>: <em>brew install curl</em></p><p><em>Curl</em> is a Swiss Army knife for transferring data. Whether testing <em>APIs</em> or downloading files, it’s a must-have for any <em>developer or network</em> engineer.</p><p>For example:</p><pre>alias ipe=&quot;curl -s ipecho.net/plain | tee &gt;(pbcopy)&quot;<br>get_info_from_ip() { # Ex: get_info_from_ip 217.160.0.196<br>    curl -s &quot;https://ipapi.co/$1/json/&quot; | jq<br>}<br>get_latest_release() { # Ex: get_latest_release laravel/laravel<br>    curl --silent &quot;https://api.github.com/repos/$1/releases/latest&quot; |<br>        grep &#39;&quot;name&quot;:&#39; |<br>        sed -E &#39;s/.*&quot;([^&quot;]+)&quot;.*/\1/&#39;<br>}</pre><p><strong>5. Eza: Modern ls Replacement</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VEaZeVL-WDNzlW3Pxaz7kw.png" /><figcaption>I love my beautiful Terminal!</figcaption></figure><p><strong>Command</strong>: <em>brew install eza</em></p><p><em>Eza</em> breathes new life into the ls command with a modern aesthetic, colorized output, and support for Git integration, too. It’s both visually appealing and packed with features.</p><p>In the capture above, command <em>ll</em> means:</p><pre>alias ll=&#39;eza -lh --git --group-directories-first -s extension --icons&#39;</pre><p><strong>6. FFmpeg: Multimedia Powerhouse</strong></p><p><strong>Command</strong>: <em>brew install ffmpeg</em></p><p><em>FFmpeg</em> is the ultimate tool for handling audio and video. From transcoding to streaming, its versatility covers almost every multimedia task you can imagine.</p><p><strong>7. fzf: Command-Line Fuzzy Finder</strong></p><p><strong>Command</strong>: <em>brew install fzf</em></p><p><a href="https://junegunn.github.io/fzf/"><em>fzf</em></a> allows you to quickly search through files, commands, and directories with its fuzzy matching algorithm. Integrating seamlessly with other tools is essential for productivity If you use it with <em>zsh</em>.</p><p><strong>8. Git: Version Control System</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qaEUEG6SKWpPS4PNwdf3mQ.png" /><figcaption>g.l, g.brs &amp; g.la make sense for me</figcaption></figure><p><strong>Command</strong>: <em>brew install git</em></p><p>No development environment is complete without <em>Git</em>. This distributed version control system is the backbone of modern software collaboration, making it essential for developers.</p><p>Some of my most used <em>Git</em> aliases:</p><pre>alias g.bah=&quot;git reset --hard; git clean -df&quot;<br>alias g.brs=&quot;git for-each-ref --sort=-committerdate refs/heads/ --format=&#39;%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))&#39;&quot;<br>alias g.l=&quot;git log --oneline --decorate --graph&quot;<br>alias g.la=&quot;git log --pretty=format:&#39;%C(yellow)%h | %ad%Cred%d | %Creset%s%Cblue | [%cn]&#39; --decorate --date=short&quot;</pre><p>You can visit my article about Git <a href="https://misapuntesde.com/2024/11/git_guide.html">here</a> on my blog!</p><p><strong>9. GnuPG: Secure Encryption</strong></p><p><strong>Command</strong>: <em>brew install gnupg</em></p><p><em>GnuPG</em> provides robust encryption for secure communication and data storage. It’s widely used for email encryption, file signing, and key management.</p><p><strong>10. Jq: JSON Processor Extraordinaire</strong></p><p><strong>Command</strong>: <em>brew install jq</em></p><p><em>Jq</em> makes working with <em>JSON</em> data a breeze. Whether formatting, querying, or transforming JSON, it’s a lifesaver for developers and data analysts.</p><p><strong>11. Ncdu: Disk Usage Analyzer</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2bLe_oNZU-1xh2kJ1Q2vEw.png" /><figcaption>Now I know where the garbage is on my filesystem.</figcaption></figure><p><strong>Command</strong>: <em>brew install ncdu</em></p><p><em>ncdu</em> is an interactive tool that provides detailed insights into disk usage. Its intuitive interface helps you identify and clean up large files and directories.</p><p><strong>12. Pyenv: Python Version Manager</strong></p><p><strong>Command</strong>: <em>brew install pyenv</em></p><p>Managing multiple <em>Python</em> versions is a breeze with <em>Pyenv</em>. It’s indispensable for developers working on diverse projects requiring different <em>Python</em> versions, but I’m migrating to <a href="https://astral.sh/blog/uv">uv</a> on my projects and using <em>Poetry</em> at work.</p><p><strong>13. Python@3.11: Cutting-Edge Python Interpreter</strong></p><p><strong>Command</strong>: <em>brew install python@3.11</em></p><p><em>macOS</em> already has <em>Python</em> installed by default. You can install the <em>Python</em> version you need. It’s the backbone of countless scripts, applications, and libraries.</p><p><strong>14. Sevenzip: High-Ratio File Compression</strong></p><p><strong>Command</strong>: <em>brew install sevenzip</em></p><p>Sevenzip delivers outstanding compression and decompression performance for various formats, making it an essential utility for handling large files efficiently.</p><p>Example for compressing and splitting a file:</p><pre>7zz a -t7z -v3500m largemovie.7z most_large_movie_ever.mkv</pre><p><strong>15. ShellCheck: Lint Tool for Shell Scripts</strong></p><p><strong>Command</strong>: <em>brew install shellcheck</em></p><p><em>ShellCheck</em> helps you write better, safer shell scripts by identifying potential bugs and offering actionable suggestions. It’s a must for anyone automating tasks.</p><p><strong>16. yt-dlp: Advanced Video/Audio Downloader</strong></p><p><strong>Command</strong>: <em>brew install yt-dlp</em></p><p>A fork of the popular youtube-dl, yt-dlp boasts additional features for downloading videos and audio from a wide array of platforms. It’s powerful, reliable, and feature-rich.</p><p>Here is an example of an alias I use to download <em>YouTube</em> videos:</p><pre>alias ydload=&#39;yt-dlp -U &amp; cd $HOME/Downloads &amp;&amp; yt-dlp --concurrent-fragments 4 -q --no-check-certificates -f &quot;bestvideo[ext=mp4]+bestaudio[ext=m4a]/best&quot; --merge-output-format mp4 --write-auto-sub --sub-lang en&#39;</pre><p><strong>17. z: Smarter Directory Traversal</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SP0w972XwZgBEMSRaIzK5w.png" /><figcaption>z + first letter of a directory = more free time in a year for procrastinating. 😎</figcaption></figure><p><strong>Command</strong>: <em>brew install z</em></p><p><em>z</em> learns your directory habits, allowing you to jump to frequently visited folders with minimal typing. It’s an invaluable timesaver for frequent navigators.</p><p>These essential <em>macOS</em> command-line applications enhance my productivity every day. Whether you’re a developer, sysadmin, or power user, these tools will elevate your <em>macOS</em> experience. 💪</p><p>I’m pretty sure you have your favorite essential tools. Keep it, and don’t show me in the comments. I don’t want to use them…</p><p>(Now is when you stop reading, go to comments, and drop all your tools like a Good Samaritan to prove your apps are the best).</p><p>Ready to supercharge your terminal? Open up your favorite shell, run brew install, and… Start exploring!</p><p>Time to clap 👏 &amp; follow me! 👯</p><p><em>On my </em><a href="https://misapuntesde.com"><em>blog</em></a><em>, you can read news/tutorials about Raspberry Pi, Linux, macOS, DevOps, development, and all the things you and I want to learn.<br>Visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>!</em></p><p><em>Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=92a4af70dae2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How I use AI as a developer today]]></title>
            <link>https://medium.com/@ulysess/how-i-use-ai-as-a-developer-today-999823027a41?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/999823027a41</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[vscode]]></category>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[github-copilot]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Tue, 25 Jun 2024 18:19:57 GMT</pubDate>
            <atom:updated>2024-06-25T18:19:57.590Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jXrzVmWw4dUbmZkAD1MAjw.jpeg" /><figcaption>MEME found at <a href="https://www.reddit.com/r/ProgrammerHumor/comments/1dg2862/igottabefaster/">r/ProgrammerHumor</a></figcaption></figure><p>I don’t tell you a lie when I advise you that if you’re not using AI in your day-to-day life, you’re missing a great opportunity.</p><p>WE CAN’T ESCAPE!.</p><p>This is moving fast and you do not need to be convinced that it can help you in all the processes you perform, in the profession you have. In this article, I’ll tell you how I use it as a developer and maybe in another article, as a writer.</p><h3>GitHub Copilot</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/679/1*H5QynWNZ59K_XJfS2u0Vhg.jpeg" /><figcaption>True, true…</figcaption></figure><p>I’m not going to spend much time telling you what I write in this section either. For $20 you have an assistant on your <em>IDE</em> that helps you write code. It’s not perfect by the way, but it saves you time and I’m impressed with the Wow 😱 effect.</p><p>Sometimes, it even gives you solutions you hadn’t thought of (and at first it makes you angry as a human that you are). It’s like the smart-ass dude who’s correcting you and giving you solutions without asking him… Funny that I came to mind <em>Eddie Deezen</em> acting in the movie <em>WarGames</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/540/1*RVBHIpUpm0XvoNbFPkM6Ig.gif" /><figcaption>You rock, Eddie Deezen! RIP.</figcaption></figure><p>Not everything is as beautiful as it seems, because sometimes it gives you solutions that are not the most optimal, and you have to review them (there are hundreds of memes about this, <a href="https:/www.reddit.com/rProgrammerHumor/s/obmhe3/ng_copilot_memes_are/are">here</a> is one 😂 ). But hey, that’s what it is this year. The next one, we’ll see…</p><p>By the way, in <em>VSCode</em> remember to install the two essential extensions to get the most out of it: <strong>GitHub Copilot and GitHub Copilot chat</strong>. You also have an extension for use with GitHub <em>Codespaces</em>, which allows you to use Copilot in the cloud.</p><p>I recommend looking at the playlists on the <em>Visual Studio Code</em> <a href="https://www.youtube.com/@code/playlists">YouTube channel</a>. I leave you some tips that I use in my day to day:</p><p>· <strong>Ideal for small scripts</strong>: It is one of the features I use most. I have created scripts to automate tasks that took time and now I have them in a snap. For example, a script that cleans the external storage systems before ejecting in <em>Rust</em> (and I don’t have much idea of this language), another that downloads <em>YouTube playlists</em>…</p><p>· <strong>Make my tests!</strong>: What we most hate as programmers, but that helps us a lot. Our friend helps you write the tests, but It’s not thinking about them. You give him a little push, you’ll see how fast the dirty work does.</p><p>· <strong>Use keyboard shortcuts</strong>: If you use <em>VSCode</em> like me, I recommend that you learn the keyboard shortcuts it offers. <em>Cmd + I</em>to ask him inline, <em>Shift + Cmd + H</em> opens the side chat so you can ask him.</p><p>· <strong><em>Use / in the chat</em></strong>: If you type / in the chat, it gives you a list of commands that you can use to improve the response. In my case, I use a lot <a href="http://twitter.com/workspace"><em>@workspace</em></a> to give me solutions according to my workspace, but you have many others: <em>/help, #file:index.html, /explain, </em><a href="http://twitter.com/vscode"><em>@vscode</em></a><em>, </em>etc.</p><p><strong>· Ask what you want</strong>: It’s an AI, so don’t be afraid: <em>How can I build this project? How do I install the dependencies? Where are the middlewares? Can you give me the secret to get rich?</em> Remember that if you don’t want generic results, you have to specify<em> </em><a href="http://twitter.com/workspace"><em>@workspace</em></a> or <a href="http://twitter.com/file"><em>@file</em></a> to get solutions that fit your workspace. It is not the same <em>build me a class Calculator</em> that <em>build me in PHP a class Calculator documenting the methods and typing the parameters.</em></p><p>· <strong>Errors in the code or Terminal</strong>: If you get an error when executing your code, you can ask <em>Copilot</em> what is happening. Select the error and paste it into the chat. If the problem comes from the terminal, select the code, press the right mouse button, and choose the <em>Explain this</em> option. You can also click on the sparkles ✨ that appear on the left of your prompt.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/443/1*9i2kYX-xNqvHkAGhgliVVA.jpeg" /><figcaption>GitHub Mobile has Copilot, too!</figcaption></figure><p>· <strong>On your smartphone, too</strong>!: If you use <em>GitHub</em> on your smartphone, you can use <em>GitHub Copilot</em>. 😍</p><p>· <strong>When all fails or doesn’t get the solution you’re looking for</strong>: Don’t get upset. What I do is create a new chat and ask again. Above all, it happened to me when he offered you code that comes from some public project. You must specify in the settings within <em>GitHub Copilot</em> that you want to (or not) give you solutions using public code by turning on or off the option <em>Suggestions matching public code (duplication detection filter)</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/579/1*KQIADgvuK2DkEMEHZGRzcA.png" /><figcaption>Let that generate the comments for your commits</figcaption></figure><p>· <strong>Let that generate the for your commits</strong>: If you don’t like to write comments for commits, tap the icon ✨. The good thing is that it is learning from your comments and will give you solutions more according to your style.</p><h3>Help in the Terminal</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3Mn2bgfA0E80PvE0n9_KeQ.png" /><figcaption>Warp AI</figcaption></figure><p>When I have to write a command I don’t know or don’t remember, I always go to <a href="https://www.warp.dev/ai">Warp</a>, the Terminal that has built-in serial AI. It’s like a <em>Copilot</em> for the <em>Terminal</em> and <strong>it’s cross-platform</strong>. If you haven’t tried it, I recommend it. So write what you want to do and it gives you the solution. Easy and fast… It’s free, but it has payment plans.</p><h4>Yes, Copilot in the Terminal!</h4><p><em>GitHub Copilot</em> can also help you with terminal commands in three different ways: you specify the word <a href="http://twitter.com/terminal">@terminal</a> before your chat question, with Cmd + I in the terminal view inside <em>VSCode</em> or you can use <a href="https://docs.github.com/en/copilot/github-copilot-in-the-cli">GitHub Copilot in the CLI</a>.</p><h3><strong>Code reviews</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gEQ8HiGz6-LkA8CNR-6oew.png" /><figcaption>Sourcery in action!</figcaption></figure><p>If you use a <em>GitHub</em> or <em>GitLab</em> account, you can incorporate <a href="https://sourcery.ai/">Sourcery</a> into your workflow. In my case, when I make a pull request, it gives me suggestions on how to improve my code. For open-source projects is free.</p><h3>AI agents</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cNdgjiEdUL-3sHoeyOhS7A.jpeg" /><figcaption>Guide of AI Agent Types with examples. <a href="https://medium.com/@thomas.latterner/guide-of-ai-agent-types-with-examples-79f94a741d44">Medium</a>.</figcaption></figure><p>Although it is not a tool that I use daily (yet), I find this concept interesting to mention. They explain it very well in <a href="https://zapier.com/blog/ai-agent/">this article</a> by <em>Zapier</em>. I’ll let my AI explain it to you:</p><blockquote>Imagine you have a bot that helps you do repetitive tasks, such as letting you know if a server is down, telling you if a pull request has been approved, or letting you know if an issue has been closed. Well, that’s what AI Agents mean.</blockquote><p>Here at Medium, you have a specific topic you can find <a href="https://medium.com/tag/ai-agent">here</a><br>. For reference, the <a href="https://github.com/reworkd/AgentGPT">AgentGPT</a> project is a good example of what I’m talking about. Check it out!</p><h3>As a learning tool</h3><p>I think it’s one of the best tools you can have to learn how to code.</p><p>In case you are starting with a new language or framework, my advice is to create a markdown file with a header type with sentences like <em>How to make a CRUD in Python</em> or <em>Introduction to Rust programming</em>. Behold how it begins to give you ideas and sections continuously.</p><h3>Tell me what you know about my PDFs</h3><p>I worked as a project manager for the last two years, and I accumulated a lot of reports. If a client requested any data, I had to look for it among hundreds of Word documents or PDFs.</p><p>When I found the <a href="https://github.com/zylon-ai/private-gpt">private-gpt</a> repo, all I had to do was ask for any information from a chat, and it was returned to me along with the name of the file where it was quickly and (almost) effective.</p><p>It is a tool that I recommend if you have to deal with many documents and your brain does not remember the commissions that were agreed on six months ago. The best: privately and locally.</p><h3>Other AI you can use</h3><p>If you are not convinced or do not want to pay for <em>GitHub Copilot</em>, there are other options.</p><p>For example, <a href="https://www.tabnine.com/">Tabnine</a> in its Basic plan, uses autocomplete code and is a <em>GitHub Copilot</em> first cousin. Another approach is <a href="https://www.deepcode.ai/">DeepCode</a>, which is a code analyzer that helps you find errors and improve your code.</p><p>The above-mentioned <em>Sourcery</em> can also help you in this regard and it is very easy to implement it. You can see the documentation for <em>VSCode</em> <a href="https://docs.sourcery.ai/Coding-Assistant/Guides/Getting-Started/VSCode/">here</a>.</p><p>Do you know <a href="https://marketplace.visualstudio.com/items?itemName=Continue.continue">Continue</a>? It is a very young extension for <em>VSCode</em> and <em>JetBrains</em>. It seems <em>Copilot</em>, but locally. That is, the model must be supplied by you using <em>Ollama</em> or similar (list of models <a href="https://docs.continue.dev/setup/select-model">here</a>). You can get more info <a href="https://www.continue.dev/">here</a>.</p><p>There are many sites specializing in AI for developers, such as <a href="https://www.phind.com/">Phind</a> or <a href="https://userway.org/get/">Userway</a>, but I recommend those you can use within your <em>IDE</em>, to make it easier to use and “learn” to give you code according to your workspace.</p><h3>Final words</h3><p>It’s funny what happens with this technology: if you don’t use it, you stay behind, and if you use it, it’s like that new co-worker who has put you aside so that you learn everything you know and the company can hire you in the future. 😅</p><p>According to some analysts, there is still a lot left for that to happen (five years!), although others believe that it is one more tool and that it will simply modify the way we interact with machines.</p><p>Allow me, in the meantime, to enjoy the advantages that it offers me to improve my writing, either of code or of prose, and to continue helping me in those works that take me more time than I would like.</p><p>As an example of what I am talking about, I have written the word <strong>we</strong>, and look at what the autocomplete of Copilot tries to convince me of:</p><blockquote>We have to be aware that AI is not the enemy, but a tool that can help us to be more efficient in our work. — 🤖</blockquote><p>Whatever you say, dude. Whatever you say… 🤦</p><p>Time to clap 👏 &amp; follow me! 👯</p><p><em>This article was published for the first time on the blog misapuntesde.com, where you can read news/tutorials about Raspberry Pi, Linux, macOS, DevOps, development, and all the things you and I want to learn.<br>I’m looking for a job, so visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>! Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=999823027a41" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Best roadmaps for developers: 2024 Edition]]></title>
            <link>https://medium.com/@ulysess/best-roadmaps-for-developers-2024-edition-138a30650bbb?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/138a30650bbb</guid>
            <category><![CDATA[php]]></category>
            <category><![CDATA[laravel]]></category>
            <category><![CDATA[roadmaps]]></category>
            <category><![CDATA[front-end-development]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Sun, 16 Jun 2024 09:18:55 GMT</pubDate>
            <atom:updated>2024-06-25T18:26:19.415Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_DqG43Jkoz5QIrHBo4FuoA.jpeg" /><figcaption>Generated with Dall-E</figcaption></figure><blockquote><strong>CONTENT UPDATED</strong>: This post was updated on June 23, 2024. 🚀</blockquote><p>The best part that you are reading my posts is that I don’t need to convince you with tons of resources like a dirty trickster to follow me. The resources I share with you are the best roadmaps for programming languages I found, now in 2024. <strong>Those are my personal preferences</strong>, and here are not all the language programming, only the ones I’m interested in according to my career, but I’m sure you will find them useful.</p><h3>Laravel</h3><p>If you like Laravel, you probably follow <em>Povilas Korop</em>, the creator of <em>Laravel Daily</em>. He has a great roadmap for <em>Laravel</em> and is very updated.</p><p><strong>Link</strong>: <a href="https://laraveldaily.com/roadmap-learning-path">laraveldaily.com/roadmap-learning-path</a></p><h3>PHP</h3><p>For <em>PHP</em>, I recommend the roadmap from <em>PHP the Wrong Way</em>. It’s a very complete guide for beginners and advanced users. You have a lot of resources and tutorials to start with <em>PHP</em>, from the basics to the advanced.</p><p><strong>Link</strong>: <a href="https://phpthewrongway.com/">phpthewrongway.com</a> | OK, here you have the link to <a href="https://phptherightway.com/">phptherightway.com</a>, too. 😉</p><h3>Front-End</h3><p>I’m not like front-end, but as a freelance, I need to know the basics. I chose the roadmap from geeksforgeeks because It’s very complete and updated. Check the tutorials and resources they provide (very useful, but ssh!… Don’t tell anyone).</p><p>They have a <a href="https://www.geeksforgeeks.org/mern-stack-development-roadmap/">MERN</a> roadmap too, but I’m not a big fan of that stack. Maybe because I haven’t used it yet. Do you recommend it?</p><p><strong>Link</strong>: <a href="https://www.geeksforgeeks.org/frontend-developer-roadmap">geeksforgeeks.org/frontend-developer-roadmap</a></p><h3>Open Source Guides</h3><p>If you are interested in contributing to open-source projects, you should check the next guides. They have a lot of resources and guides: Starting an open source project, contributing, licensing, best practices, and more.</p><p>Coded with ❤️ by <em>GitHub</em> and friends.</p><p><strong>Link</strong>: <a href="https://opensource.guide/">opensource.guide</a></p><h3>Developer roadmaps</h3><p>If you are a developer, you should check the roadmap from <a href="https://kamranahmed.info/">Kamran Ahmeds</a>. It’s a very complete guide for people like you. From role to basic &amp; advanced skill.</p><p><strong>Link</strong>: <a href="https://roadmap.sh/">roadmap.sh</a></p><p>I will leave you with another great resource called <em>Exercism</em>: A platform that provides coding exercises for different programming languages. Practice your skills and learn new languages.</p><p><strong>Link</strong>: <a href="https://exercism.org/">exercism.org</a></p><h3>DSA</h3><p>Many developers always recommend learning Data Structures and Algorithms with the <em>Princeton University</em> courses. I’m not a big fan of those courses (and they are a bit boring). If you are interested in this topic, you really should check the roadmap from <a href="https://www.techiedelight.com/data-structures-and-algorithms-problems/">Techie Delight</a>. They have a lot of resources and tutorials with practical examples and multi lingual.</p><h3>Final thoughts</h3><p>Being a developer or starting a new career in programming is a challenge. Sometimes you can feel overwhelmed, but with the right resources, you can achieve your goals.</p><p>I forgot to mention If you are a complete newbie, you should check the <a href="https://cs50.harvard.edu/x/2024/weeks/0/">CS50’s Introduction to Computer Science</a> from <em>Harvard</em> University. It’s a great course to start with the right foot.</p><p>I’m sure you will find this post useful, so add it to your bookmark right now! 😄</p><p><em>This article was published for the first time on the blog </em><a href="https://misapuntesde.com/2024/06/best_roadmaps_for_programming_languages_2024_edition.html"><em>misapuntesde.com</em></a><em>, where you can read news/tutorials about Raspberry Pi, Linux, macOS, DevOps, development, and all the things you and I want to learn.<br>I’m looking for a job, so visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>! Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=138a30650bbb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Keep your macOS apps updated with these free apps]]></title>
            <link>https://medium.com/@ulysess/keep-your-macos-apps-updated-with-these-free-apps-1c5983e2ea99?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/1c5983e2ea99</guid>
            <category><![CDATA[application]]></category>
            <category><![CDATA[software]]></category>
            <category><![CDATA[apps]]></category>
            <category><![CDATA[macos]]></category>
            <category><![CDATA[updates]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Thu, 13 Jun 2024 16:53:44 GMT</pubDate>
            <atom:updated>2024-06-16T08:32:11.940Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U53AnjTsmxLt5CKKBC7y6Q.png" /><figcaption>My apps to get my OS to the latest</figcaption></figure><p>I have a problem with the software on my OS, maybe It’s a disease, I don’t know. The reason:</p><p><strong>I NEED TO KEEP ALL MY APPS UPDATED</strong></p><p>I try not to have many of them, but the apps I have installed need the latest updates. How do I get it? With some apps that help me on that mission. Do you want to know which ones? Keep reading!</p><h3><strong>Latest</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cWBJL6kw3munIFzToALQrQ.jpeg" /><figcaption>Latest screenshot</figcaption></figure><p><em>Latest</em> is a free and open-source app that checks if all your apps are up to date. It’s a simple app that shows you a list of all your installed apps and the latest version available.</p><p>You can update them with a single click or one by one. It supports apps downloaded from the <em>Mac App Stor</em>e and apps that use <em>Sparkle</em> for updates, which covers most of the apps on the market.</p><p>If the app is not supported, you can open the app through <em>Latest</em> and check for updates manually.</p><p>Link: <a href="https://github.com/mangerlahn/Latest">github.com &gt; Latest</a></p><h3>Cork</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NNLNZZtYsBBnWkEXaIWO0w.jpeg" /><figcaption>Cork</figcaption></figure><p>It’s a fast GUI for Homebrew apps!</p><p>In the past, I used to update my apps with the terminal, but with Cork, I can do it with a single click (even when I love the <em>Terminal</em>).</p><p>It’s a paid app, but you have the chance to compile and use it for free. It has many other features to handle visually your Homebrew apps: search, fix, install, uninstall,…</p><p>It just works &amp; It’s a great tool to keep your apps updated. Dot.</p><p>Link: <a href="https://github.com/buresdv/Cork">github.com &gt; Cork</a></p><h3>Python cleanup script for macOS</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/653/1*JH1GCn8yNN5GyDXPGDjzjQ.png" /><figcaption>mac-cleanup-py</figcaption></figure><p><em>mac-cleanup-py</em> is a powerful cleanup script for <em>macOS</em>. It helps you in the next tasks: Empty Trash, delete unnecessary logs &amp; files and clear cache from <em>OS</em> or some apps. You can enable specific apps to clean up, like <em>Xcode</em> or <em>Android Studio</em>. It has a very useful dry mode to see what it will do before running it.</p><p>Link: <a href="https://github.com/mac-cleanup/mac-cleanup-py">github.com &gt; mac-cleanup-py</a></p><h3>Custom function</h3><p>So I think this is something all developers should have in their <em>.*rc </em>file: A simple function that checks if there are any updates available for the installed apps. For example, I use this function in my <em>.zshrc</em> file:</p><pre>update_all() {<br>    if [[ -f /usr/local/bin/composer ]]; then<br>        composer self-update<br>        composer global update<br>    fi<br><br>    softwareupdate --all --install --force<br>    brew outdated &amp;&amp; brew update &amp;&amp; brew upgrade &amp;&amp; brew cleanup<br>    ## Add yours here!<br>}</pre><h3>Conclusion</h3><p>Now you have no excuse to keep your <em>macOS</em> updated. Of course, you can still use manual methods, but with these apps, you can have more control over the process in less time. Do you use any other app to achieve that? Let me know! 😃</p><p><em>This article was published for the first time on the blog </em><a href="https://misapuntesde.com/2024/06/keep_your_macos_updated_with_these_free_apps.html"><em>misapuntesde.com</em></a><em>, where you can read news/tutorials about Raspberry Pi, Linux, macOS, DevOps, development, and all the things you and I want to learn.<br>I’m looking for a job, so visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>! Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1c5983e2ea99" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SOLID principles PHP Edition. Today, Dependency Inversion Principle]]></title>
            <link>https://medium.com/@ulysess/solid-principles-php-edition-today-dependency-inversion-principle-b3f86f31c39c?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/b3f86f31c39c</guid>
            <category><![CDATA[solid-principles]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[solid]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Tue, 21 May 2024 07:53:33 GMT</pubDate>
            <atom:updated>2024-05-21T07:53:33.975Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FNsUVihcBKtjje-oQMPujA.jpeg" /><figcaption>Dependency Inversion Principle. Generated with AI and modified later.</figcaption></figure><p>Finally, we reach the last principle of the <strong>SOLID</strong> series. The <strong>Dependency Inversion Principle</strong> is the most complex of all, but I’ll try to explain it in a simple way.</p><p>I remember being asked about this principle in a recent job interview and I didn’t know what to say. Many times you know what it is by concept, but explaining it with an example (in English, which is not my tongue language) is hard. If it happens to you, the best thing to do is to be honest and say so. It’s okay and the interviewer will appreciate it.</p><p>Let’s review all the principles we have seen:</p><p><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-single-responsibility-principle-5897edcfbdb3"><em>Single Responsibility Principle</em></a>: A class should have only one reason to change.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-open-closed-principle-896cbb3c8dce">Open/Closed Principle</a>: A class should be open for extension but closed for modification.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-liskov-substitution-principle-661b1f343bbe"><em>Liskov Substitution Principle</em></a>: You should be able to use any subclass in place of its parent class.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-interface-segregation-principle-a9bd3663ba32"><em>Interface Segregation Principle</em></a>: A class should not be forced to implement an interface it doesn’t use.<br><em>Dependency Inversion Principle</em>: High-level modules should not depend on low-level modules. Both should depend on abstractions.</p><p>The Dependency Inversion Principle states that <strong>high-level modules should not depend on low-level modules. Both should depend on abstractions.</strong> Also, abstractions should not depend on details. Details should depend on abstractions. A lot of words, I know, but we’ll look at it right now. Besides, I think this principle is the one that will help you the most in the long run.</p><p>Let’s see some examples to better understand it:</p><pre>// Bad<br>class MySQLConnection {<br>    public function connect() {<br>        return &quot;Database connection&quot;;<br>    }<br>}<br><br>class PasswordReminder {<br>    private $dbConnection;<br><br>    public function __construct(MySQLConnection $dbConnection) {<br>        $this-&gt;dbConnection = $dbConnection;<br>    }<br>}</pre><p>In this example, the <em>PasswordReminder</em> class depends on the <em>MySQLConnection</em> class. If you want to change the database connection to another type, <strong>you will have to modify the <em>PasswordReminder</em> class</strong>. This does not follow the <em>Dependency Inversion Principle</em>.</p><p>To solve this, <strong>you can use an interface</strong>:</p><pre>interface DBConnectionInterface {<br>    public function connect();<br>}<br><br># The MySQLConnection class implements this interface, providing its own implementation of the connect() method.<br>class MySQLConnection implements DBConnectionInterface {<br>    public function connect() {<br>        return &quot;Database connection&quot;;<br>    }<br>}<br><br>class PasswordReminder {<br>    private $dbConnection;<br><br>    public function __construct(DBConnectionInterface $dbConnection) {<br>        $this-&gt;dbConnection = $dbConnection;<br>    }<br>}</pre><p>Now, the <em>PasswordReminder</em> class depends on the <em>DBConnectionInterface</em> interface, not on the <em>MySQLConnection</em> class. If you want to change the database connection, you only need to create a new class that implements the <em>DBConnectionInterface</em> interface. This makes <em>PasswordReminder</em> more flexible and less coupled to a specific database connection implementation.</p><p>Do you not find it easy? Let’s see another example:</p><pre>interface StorageInterface {<br>    public function save($data);<br>}<br><br>class FileStorage implements StorageInterface {<br>    public function save($data) {<br>        // Save data to a file<br>    }<br>}<br><br>class DatabaseStorage implements StorageInterface {<br>    public function save($data) {<br>        // Save data to a database<br>    }<br>}<br><br>class UserController {<br>    private $storage;<br><br>    public function __construct(StorageInterface $storage) {<br>        $this-&gt;storage = $storage;<br>    }<br><br>    public function store($data) {<br>        $this-&gt;storage-&gt;save($data);<br>    }<br>}<br><br>$fileStorage = new FileStorage();<br>$userController = new UserController($fileStorage);<br>$userController-&gt;store(&quot;Some data&quot;);</pre><p>In this example, the <em>UserController</em> class depends on the <em>StorageInterface</em> interface, not on the <em>FileStorage</em> or <em>DatabaseStorage</em> classes. This allows you to easily change the storage type without having to modify the <em>UserController</em> class.</p><p>We also note that <em>UserController</em> does not know how information is stored (details), it only knows that it is stored. The <em>DatabaseStorage</em> and FileStorage classes are the details and depend on the <em>StorageInterface</em> abstraction.</p><p>I hope you have enjoyed the last article about <strong>SOLID principles</strong>. In the future, I plan to investigate other design patterns.</p><p>Stay tuned! 😄</p><p><em>This article was published for the first time on the blog </em><a href="https://misapuntesde.com/2024/04/solid_principles_php_edition_dependency_inversion_principle.html"><em>misapuntesde.com</em></a><em>, where you can read news/tutorials about Raspberry Pi &amp; Linux, and soon about Mac, DevOps, development, and all the things you and I want to learn.<br>I’m looking for a job, so visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>! Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b3f86f31c39c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SOLID principles PHP Edition. Today, Interface Segregation Principle]]></title>
            <link>https://medium.com/@ulysess/solid-principles-php-edition-today-interface-segregation-principle-a9bd3663ba32?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/a9bd3663ba32</guid>
            <category><![CDATA[code]]></category>
            <category><![CDATA[solid-principles]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[solid]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Tue, 30 Apr 2024 09:26:00 GMT</pubDate>
            <atom:updated>2024-05-21T07:57:16.811Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LxSPgEji2J998skwLychNQ.jpeg" /><figcaption>Interface Segregation Principle. Generated with AI.</figcaption></figure><p>We are almost ending the series of articles about the SOLID principles. Here you have a brief explanation of each principle to review them:</p><p><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-single-responsibility-principle-5897edcfbdb3"><em>Single Responsibility Principle</em></a>: A class should have only one reason to change.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-open-closed-principle-896cbb3c8dce"><em>Open/Closed Principle</em></a>: A class should be open for extension but closed for modification.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-liskov-substitution-principle-661b1f343bbe"><em>Liskov Substitution Principle</em></a>: You should be able to use any subclass in place of its parent class.<br><em>Interface Segregation Principle</em>: A class should not be forced to implement an interface it doesn’t use.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-dependency-inversion-principle-b3f86f31c39c"><em>Dependency Inversion Principl</em></a><em>e</em>: High-level modules should not depend on low-level modules. Both should depend on abstractions.</p><p>Today we are going to focus on the Interface Segregation Principle. It’s very easy to understand, I promise. ❤️</p><p>This principle states that <strong>a class should never be forced to implement an interface that it doesn’t use</strong>. If you implement an interface in a class, but only utilize a few of its methods, It indicates that you are violating this principle. An Example:</p><pre>// Bad<br>interface Bird {<br>    public function fly();<br>    public function swim();<br>}<br><br>class Eagle implements Bird {<br>    public function fly() {<br>        return &quot;I can fly&quot;;<br>    }<br>    public function swim() { &lt;- Forced to implement a method that it does not need<br>        return &quot;I can&#39;t swim&quot;;<br>    }<br>}<br><br>class Penguin implements Bird {<br>    public function fly() { &lt;- Forced to implement a method that it does not need<br>        return &quot;I can&#39;t fly&quot;;<br>    }<br>    public function swim() {<br>        return &quot;I can swim&quot;;<br>    }<br>}</pre><p>In this example, the <em>Bird</em> interface has two methods: <em>fly</em> and <em>swim</em>.</p><p>The <em>Eagle</em> and the <em>Penguin</em> classes implement both methods, but the <em>Penguin</em> class only should implement the <em>swim</em> method (Have you ever seen a penguin flying?), and <em>Eagle</em> should implement the <em>fly</em> method. This violates the <em>Interface Segregation Principle</em>.</p><p>An example of the correct way to implement the Interface Segregation Principle:</p><pre>// Good<br>interface Bird {<br>    public function fly();<br>}<br><br>interface Swimmer {<br>    public function swim();<br>}<br><br>class Eagle implements Bird {<br>    public function fly() {<br>        return &quot;I can fly&quot;;<br>    }<br>}<br><br>class Penguin implements Swimmer {<br>    public function swim() {<br>        return &quot;I can swim&quot;;<br>    }<br>}</pre><p>Now we have two interfaces: <em>Bird</em> and <em>Swimmer</em>. The <em>Eagle</em> class implements the <em>Bird</em> interface, and the <em>Penguin</em> class implements the <em>Swimmer</em> interface. This way, we are following the principle we are discussing. Easy, right? 😄</p><p><em>This article was published for the first time on the blog </em><a href="https://misapuntesde.com/2024/04/solid_principles_php_edition_interface_segregation_principle.html"><em>misapuntesde.com</em></a><em>, where you can read news/tutorials about Raspberry Pi &amp; Linux, and soon about Mac, DevOps, development, and all the things you and I want to learn.</em></p><p><em>I’m looking for a job, so visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>! Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a9bd3663ba32" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SOLID principles PHP Edition. Today, Liskov Substitution Principle]]></title>
            <link>https://medium.com/@ulysess/solid-principles-php-edition-today-liskov-substitution-principle-661b1f343bbe?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/661b1f343bbe</guid>
            <category><![CDATA[code]]></category>
            <category><![CDATA[solid-principles]]></category>
            <category><![CDATA[solid]]></category>
            <category><![CDATA[php]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Tue, 23 Apr 2024 10:11:05 GMT</pubDate>
            <atom:updated>2024-05-21T07:59:04.530Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aIGbp_zPjv2Mg-tyXWZmjw.jpeg" /><figcaption>Liskov Substitution Principle. Generated with AI.</figcaption></figure><p>In the noble art of coding, you should remember the SOLID principles always. Sometimes, I forget some of them, so here is a brief explanation of each principle:</p><p><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-single-responsibility-principle-5897edcfbdb3"><em>Single Responsibility Principle</em></a>: A class should have only one reason to change.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-open-closed-principle-896cbb3c8dce"><em>Open/Closed Principle</em></a>: A class should be open for extension but closed for modification.<br><em>Liskov Substitution Principle</em>: You should be able to use any subclass in place of its parent class.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-interface-segregation-principle-a9bd3663ba32"><em>Interface Segregation Principle</em></a>: A class should not be forced to implement an interface it doesn’t use.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-dependency-inversion-principle-b3f86f31c39c"><em>Dependency Inversion Principle</em></a>: High-level modules should not depend on low-level modules. Both should depend on abstractions.</p><p>Today we are going to focus on the Liskov Substitution Principle.</p><p>This principle states that “<strong>functions that use pointers or references to base classes must be able to use objects of a derived class without knowing it</strong>”.</p><p>In other words, derived classes must be completely substitutable for their base classes. If a derived class cannot be substituted for a base class, then the class hierarchy is not well designed and violates <em>Liskov’s substitution principle</em>.</p><p>Here you have an example of PHP about it:</p><pre>// Bad<br><br>class Bird {<br>    public function fly() {<br>        return &quot;I can fly&quot;;<br>    }<br>}<br><br>class Penguin extends Bird {<br>    public function fly() {<br>        return &quot;I can&#39;t fly&quot;;<br>    }<br>}<br><br>function letItFly(Bird $bird) {<br>    return $bird-&gt;fly();<br>}<br><br>echo letItFly(new Bird()); // &quot;I can fly&quot;<br>echo letItFly(new Penguin()); // &quot;I can&#39;t fly&quot;</pre><p>In this example, <em>Penguin</em> is a subclass of <em>Bird</em>. However, not all birds can fly, so when we try to make a <em>Penguin</em> fly, we get an unexpected result. This violates<em> Liskov’s substitution principle</em>.</p><p>A better way to do this would be to have a <em>Bird</em> base class and a <em>Flyable</em> interface that only implement birds that can fly:</p><pre>class Bird {<br>}<br><br>interface Flyable {<br>  public function fly();<br>}<br><br>class Sparrow extends Bird implements Flyable {<br>  public function fly() {<br>    return &quot;I can fly&quot;;<br>  }<br>}<br><br>class Penguin extends Bird {<br>}<br><br>function letItFly(Flyable $bird) {<br>  return $bird-&gt;fly();<br>}<br><br>echo letItFly(new Sparrow()); // &quot;I can fly&quot;</pre><p>In this example, if we try to fly a <em>Penguin</em>, we will get a compile-time error, because <em>Penguin</em> does not implement the <em>Flyable</em> interface.</p><p>Another example:</p><pre>// Bad<br><br>class Animal {<br>  public function eat() {<br>    return &quot;I can eat&quot;;<br>  }<br>}<br><br>class Lion extends Animal {<br>  public function eat() {<br>    return &quot;I can eat meat&quot;;<br>  }<br>}<br><br>class Rabbit extends Animal {<br>  public function eat() {<br>    return &quot;I can eat vegetables&quot;;<br>  }<br>}<br><br>class Plant extends Animal {<br>  public function eat() {<br>    throw new Exception(&quot;Plants do not eat&quot;);<br>  }<br>}<br><br>function feed(Animal $animal) {<br>  return $animal-&gt;eat();<br>}<br><br>echo feed(new Lion()); // &quot;I can eat meat&quot;<br>echo feed(new Rabbit()); // &quot;I can eat vegetables&quot;<br>echo feed(new Plant()); // Exception: Plants do not eat<br><br>// Good<br><br>class LivingEntity {<br>}<br><br>interface Eatable {<br>  public function eat();<br>}<br><br>class Lion extends LivingEntity implements Eatable {<br>  public function eat() {<br>    return &quot;I can eat meat&quot;;<br>  }<br>}<br><br>class Rabbit extends LivingEntity implements Eatable {<br>  public function eat() {<br>    return &quot;I can eat vegetables&quot;;<br>  }<br>}<br><br>class Plant extends LivingEntity {<br>}<br><br>function feed(Eatable $entity) {<br>  return $entity-&gt;eat();<br>}<br><br>echo feed(new Lion()); // &quot;I can eat meat&quot;<br>echo feed(new Rabbit()); // &quot;I can eat vegetables&quot;</pre><p>I hope we can understand the principle. See you in the next one! 😉</p><p><em>This article was published for the first time on the blog </em><a href="https://misapuntesde.com/2024/04/solid_principles_php_edition_liskov_substitution_principle.html"><em>misapuntesde.com</em></a><em>, where you can read news/tutorials about Raspberry Pi &amp; Linux, and soon about Mac, DevOps, development, and all the things you and I want to learn.</em></p><p><em>I’m looking for a job, so visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>! Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=661b1f343bbe" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SOLID principles PHP Edition. Today, Open/Closed Principle]]></title>
            <link>https://medium.com/@ulysess/solid-principles-php-edition-today-open-closed-principle-896cbb3c8dce?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/896cbb3c8dce</guid>
            <category><![CDATA[solid-principles]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[solid]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Thu, 18 Apr 2024 20:38:32 GMT</pubDate>
            <atom:updated>2024-05-21T07:59:51.704Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HTXGRPboy9vv1lXePJ8iSQ.jpeg" /><figcaption>Open/Closed Principle. Generated with AI.</figcaption></figure><p>First of all, here you have the four principles of SOLID:</p><p><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-single-responsibility-principle-5897edcfbdb3"><em>Single Responsibility Principle</em></a>: A class should have only one reason to change.<br><em>Open/Closed Principle</em>: A class should be open for extension but closed for modification.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-liskov-substitution-principle-661b1f343bbe"><em>Liskov Substitution Principle</em></a>: You should be able to use any subclass in place of its parent class.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-interface-segregation-principle-a9bd3663ba32"><em>Interface Segregation Principle</em></a>: A class should not be forced to implement an interface it doesn’t use.<br><a href="https://medium.com/@ulysess/solid-principles-php-edition-today-dependency-inversion-principle-b3f86f31c39c"><em>Dependency Inversion Principle</em></a>: High-level modules should not depend on low-level modules. Both should depend on abstractions.</p><p>The <em>Open/Closed</em> principle states that “<strong>software entities (classes, modules, functions, etc.) must be open for extension, but closed for modification</strong>”. So, once a software entity is developed and tested, it should be possible to extend its behavior without having to modify its source code.</p><p>Look at the following code:</p><pre>class Rectangle {<br>  public $width;<br>  public $height;<br><br>  public function __construct($width, $height) {<br>    $this-&gt;width = $width;<br>    $this-&gt;height = $height;<br>  }<br>}<br><br>class Circle {<br>  public $radius;<br><br>  public function __construct($radius) {<br>    $this-&gt;radius = $radius;<br>  }<br>}<br><br>class AreaCalculator {<br>  public function calculate($shapes) {<br>    $area = [];<br>    foreach ($shapes as $shape) {<br>      if ($shape instanceof Rectangle) {<br>        $area[] = $shape-&gt;width * $shape-&gt;height;<br>      } elseif ($shape instanceof Circle) {<br>        $area[] = $shape-&gt;radius * $shape-&gt;radius * pi();<br>      }<br>    }<br><br>    return array_sum($area);<br>  }<br>}</pre><p>In this example, if you wanted to add a new form, you would have to modify the <em>AreaCalculator</em> class and add a new condition in the <em>calculate</em> method. In other words, <em>Open/Closed principle</em> says that <strong>you should be able to add new functionality to a class without modifying it</strong>.</p><p>The example above<strong><em> violates the Open/Closed principle</em></strong>.</p><p>A better way to do this would be to define an <em>area</em> method in each form and then call that method in <em>AreaCalculator</em>:</p><pre>interface Shape {<br>  public function area();<br>}<br><br>class Rectangle implements Shape {<br>  public $width;<br>  public $height;<br><br>  public function __construct($width, $height) {<br>    $this-&gt;width = $width;<br>    $this-&gt;height = $height;<br>  }<br><br>  public function area() {<br>    return $this-&gt;width * $this-&gt;height;<br>  }<br>}<br><br>class Circle implements Shape {<br>  public $radius;<br><br>  public function __construct($radius) {<br>    $this-&gt;radius = $radius;<br>  }<br><br>  public function area() {<br>    return $this-&gt;radius * $this-&gt;radius * pi();<br>  }<br>}<br><br>class AreaCalculator {<br>  public function calculate($shapes) {<br>    $area = [];<br>    foreach ($shapes as $shape) {<br>      $area[] = $shape-&gt;area();<br>    }<br><br>    return array_sum($area);<br>  }<br>}</pre><p>Now, if you wanted to add a new form, you would just have to create a new class that implements the <em>Shape</em> interface and defines the <em>area</em> method. The <em>AreaCalculator</em> class would not have to be modified to accommodate the new form. Therefore, it would comply with the <em>Open/Closed principle</em>.</p><p><em>This article was published for the first time on the blog </em><a href="https://misapuntesde.com/2024/03/solid_principles_php_edition_open_closed_principle.html"><em>misapuntesde.com</em></a><em>, where you can read news/tutorials about Raspberry Pi &amp; Linux, and soon about Mac, DevOps, development, and all the things you and I want to learn.</em></p><p><em>I’m looking for a job, so visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>! Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=896cbb3c8dce" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SOLID principles PHP Edition. Today: Single Responsibility Principle]]></title>
            <link>https://medium.com/@ulysess/solid-principles-php-edition-today-single-responsibility-principle-5897edcfbdb3?source=rss-f764afd69244------2</link>
            <guid isPermaLink="false">https://medium.com/p/5897edcfbdb3</guid>
            <category><![CDATA[solid-principles]]></category>
            <category><![CDATA[solid]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[code]]></category>
            <dc:creator><![CDATA[Jose Cerrejon]]></dc:creator>
            <pubDate>Tue, 09 Apr 2024 08:24:02 GMT</pubDate>
            <atom:updated>2024-05-21T08:00:37.674Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7KdWRXqPSWTtVhY1XHbl6w.jpeg" /><figcaption>Single Responsibility Principle. Generated with AI.</figcaption></figure><p>In the noble art of coding, you should remember the <strong>SOLID principles</strong> always. Here is a brief explanation of each principle:</p><p>· <em>Single Responsibility Principle</em>: A class should have only one reason to change.<br>· <a href="https://misapuntesde.com/2024/03/solid_principles_php_edition_open_closed_principle.html"><em>Open/Closed Principle</em></a>: A class should be open for extension but closed for modification.<br>· <a href="https://medium.com/@ulysess/solid-principles-php-edition-today-liskov-substitution-principle-661b1f343bbe"><em>Liskov Substitution Principle</em></a>: You should be able to use any subclass in place of its parent class.<br>· <a href="https://medium.com/@ulysess/solid-principles-php-edition-today-interface-segregation-principle-a9bd3663ba32"><em>Interface Segregation Principle</em></a>: A class should not be forced to implement an interface it doesn’t use.<br>· <a href="https://medium.com/@ulysess/solid-principles-php-edition-today-dependency-inversion-principle-b3f86f31c39c"><em>Dependency Inversion Principle</em></a>: High-level modules should not depend on low-level modules. Both should depend on abstractions.</p><p>Today, we are going to focus on the <em>Single Responsibility Principle</em>.</p><p>Here you have an example of <em>PHP</em> about it:</p><pre>class Order<br>{<br>    private $items = [];<br><br>    public function addItem($item)<br>    {<br>        $this-&gt;items[] = $item;<br>    }<br><br>    public function calculateTotal()<br>    {<br>        $total = 0;<br>        foreach ($this-&gt;items as $item) {<br>            $total += $item-&gt;getPrice();<br>        }<br>        return $total;<br>    }<br>}<br><br>class Item<br>{<br>    private $name;<br>    private $price;<br><br>    public function __construct($name, $price)<br>    {<br>        $this-&gt;name = $name;<br>        $this-&gt;price = $price;<br>    }<br><br>    public function getPrice()<br>    {<br>        return $this-&gt;price;<br>    }<br>}<br><br>$item1 = new Item(&#39;Taco&#39;, 2.99);<br>$item2 = new Item(&#39;Burrito&#39;, 4.99);<br><br>$order = new Order();<br>$order-&gt;addItem($item1);<br>$order-&gt;addItem($item2);<br><br>$total = $order-&gt;calculateTotal();<br>echo &quot;Total: $&quot; . $total; // Total: $7.98</pre><p>The<em> Single Responsibility Principle (SRP)</em> states that a class must have only one reason to change. This means that<strong> a class must have only one responsibility and must have no more than one reason to be modified</strong>.</p><p>In the code above, we can identify two classes: <em>Order and Item</em>. These classes follow the principle of single responsibility, as each has a single responsibility and has no more than one reason to change.</p><p>The <em>Order</em> class is responsible for representing an order and performing operations related to it, such as adding elements to the order calculating the total, and handling the logic of the order.</p><p>The <em>Item</em> class represents an item and provides methods for obtaining its price. It has the responsibility to represent an article and provide information about it.</p><p>As we can see, each class has a unique responsibility and there is no mix of features in any of them.</p><p>This is beneficial because if in the future we need to make changes in the logic of the order, we just need to modify the <em>Order</em> class. Similarly, if we need to make changes in the representation or behavior of an article, we just need to modify the <em>Item</em> class. This facilitates code maintenance and reduces the risk of errors when making changes.</p><p>I hope this example helps you to understand the principle of single responsibility and how to apply it in your code. 🙂</p><p><em>This article was published for the first time on the blog </em><a href="https://misapuntesde.com/2024/03/solid_principles_php_edition_single_responsibility_principle.html"><em>misapuntesde.com</em></a><em>, where you can read news/tutorials about Raspberry Pi &amp; Linux, and soon about Mac, DevOps, development, and all the things you and I want to learn.</em></p><p><em>I’m looking for a job, so visit my LinkedIn profile </em><a href="https://www.linkedin.com/in/jmcerrejon/"><em>here</em></a><em>! Thank you!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5897edcfbdb3" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>