Congratulations!

[Valid RSS] This is a valid RSS feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: https://fsiblog.io/feed/

  1. <?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
  2. xmlns:content="http://purl.org/rss/1.0/modules/content/"
  3. xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  4. xmlns:dc="http://purl.org/dc/elements/1.1/"
  5. xmlns:atom="http://www.w3.org/2005/Atom"
  6. xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
  7. xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  8. xmlns:media="http://search.yahoo.com/mrss/" >
  9.  
  10. <channel>
  11. <title>FSIBLOG</title>
  12. <atom:link href="https://fsiblog.io/feed/" rel="self" type="application/rss+xml" />
  13. <link>https://fsiblog.io</link>
  14. <description>Future Stack Innovations Blog</description>
  15. <lastBuildDate>Tue, 29 Apr 2025 05:26:28 +0000</lastBuildDate>
  16. <language>en-US</language>
  17. <sy:updatePeriod>
  18. hourly </sy:updatePeriod>
  19. <sy:updateFrequency>
  20. 1 </sy:updateFrequency>
  21. <generator>https://wordpress.org/?v=6.7.2</generator>
  22.  
  23. <image>
  24. <url>https://fsiblog.io/wp-content/uploads/2024/09/FSIBLOG-Logo-150x150.webp</url>
  25. <title>FSIBLOG</title>
  26. <link>https://fsiblog.io</link>
  27. <width>32</width>
  28. <height>32</height>
  29. </image>
  30. <site xmlns="com-wordpress:feed-additions:1">241886150</site> <item>
  31. <title>How to Build a Tiny Python App That Reminds Me to Take Breaks</title>
  32. <link>https://fsiblog.io/how-to-build-a-tiny-python-app-that-reminds-me-to-take-breaks/</link>
  33. <comments>https://fsiblog.io/how-to-build-a-tiny-python-app-that-reminds-me-to-take-breaks/#respond</comments>
  34. <dc:creator><![CDATA[Daniyal Ahmed]]></dc:creator>
  35. <pubDate>Tue, 29 Apr 2025 05:26:26 +0000</pubDate>
  36. <category><![CDATA[Python]]></category>
  37. <category><![CDATA[Build a Tiny Python App That Reminds Me to Take Breaks]]></category>
  38. <category><![CDATA[How to Build a Tiny Python App That Reminds Me]]></category>
  39. <guid isPermaLink="false">https://fsiblog.io/?p=2188</guid>
  40.  
  41. <description><![CDATA[Spending all day at a screen is brutal on the eyes, the back, and the brain. So I decided to whip up a desktop toast that nudges me every hour to stand, stretch, sip water anything except keep slouch-coding. What started as seven lines of Python turned into a surprisingly fun mini-project that now lives [&#8230;]]]></description>
  42. <content:encoded><![CDATA[<p><br>Spending all day at a screen is brutal on the eyes, the back, and the brain. So I decided to whip up a <strong>desktop toast</strong> that nudges me every hour to stand, stretch, sip water <em>anything</em> except keep slouch-coding. What started as seven lines of Python turned into a surprisingly fun mini-project that now lives in my toolbox.</p><ul class="wp-block-list"><li><em>“I only intended to write one quick script… then I fell down the rabbit-hole.”</em></li></ul><p>Below is the journey, the full code, and a handful of ideas you can riff on.</p><h2 class="wp-block-heading">Define Code</h2><pre class="wp-block-preformatted"><code>from plyer import notification<br><br>if __name__ == "__main__":<br>    while True:<br>        notification.notify(<br>            title="ALERT!!!",<br>            message="Take a break! It has been an hour!",<br>        )<br>        time.sleep(3600)<br></code></pre><p>Install the only dependency:</p><pre class="wp-block-preformatted"><code>pip install plyer</code></pre><p>and run:</p><pre class="wp-block-preformatted"><code>python break.py</code></pre><p>Your OS pops up a toast every 60 minutes. Job done kind of.</p><h2 class="wp-block-heading">What each line is doing</h2><figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>#</th><th>Code</th><th>Why it matters</th></tr></thead><tbody><tr><td>1</td><td><code>import time</code></td><td>Gives me <code>time.sleep()</code> so the script can nap between alerts.</td></tr><tr><td>2</td><td><code>from plyer import notification</code></td><td><strong>plyer</strong> wraps each platform’s native “toast” API—works on Windows, macOS, Linux.</td></tr><tr><td>4</td><td><code>if __name__ == "__main__":</code></td><td>Runs the loop only when I execute the file directly, not when I import it elsewhere.</td></tr><tr><td>5</td><td><code>while True:</code></td><td>Endless loop until I hit <strong>Ctrl +C</strong>.</td></tr><tr><td>6-8</td><td><code>notification.notify(...)</code></td><td>Fires the visual reminder.</td></tr><tr><td>10</td><td><code>time.sleep(3600)</code></td><td>Waits one hour (3 600 s) before the next pass.</td></tr></tbody></table></figure><p>Great for a proof-of-concept; painful in real life. I wanted:</p><ul class="wp-block-list"><li>Flexible intervals (<code>--interval 20m</code>, <code>2h</code>, <code>90s</code>…)</li>
  43.  
  44. <li>Custom titles/messages</li>
  45.  
  46. <li>A finite number of pings (helpful in pomodoro workflows)</li>
  47.  
  48. <li>Random healthy-habit tips if I’m lazy</li>
  49.  
  50. <li>A gentle console beep (toast may be hidden)</li>
  51.  
  52. <li>Tidy logging with timestamps</li>
  53.  
  54. <li>Graceful shutdown no ugly tracebacks when I quit</li></ul><h2 class="wp-block-heading">Level-up: the extended script</h2><p>Below is <strong>break_timer.py</strong> in full, then read on for usage examples.</p><pre class="wp-block-preformatted"><code>#!/usr/bin/env python3<br>"""<br>break_timer.py – flexible desktop break-reminder<br>"""<br>import argparse<br>import datetime as dt<br>import random<br>import sys<br>import time<br>from plyer import notification<br><br># ---------- tiny knowledge base ----------<br>_TIPS = [<br>    "Stand up and stretch your legs &#x1f9b5;",<br>    "Look away from the screen for 20 seconds &#x1f440;",<br>    "Roll your shoulders a few times &#x1f646;&#x200d;&#x2642;",<br>    "Drink a glass of water &#x1f4a7;",<br>    "Take three slow, deep breaths &#x1f62e;&#x200d;&#x1f4a8;",<br>]<br><br>def parse_interval(text: str) -> int:<br>    """Turn '45m', '2h', '30s' into seconds (int)."""<br>    units = {'s': 1, 'm': 60, 'h': 3600}<br>    if text[-1].isdigit():        # default to minutes<br>        return int(text) * 60<br>    value, unit = int(text[:-1]), text[-1].lower()<br>    if unit not in units:<br>        raise ValueError("Use s, m or h as units.")<br>    return value * units[unit]<br><br>def beep() -> None:<br>    """Cross-platform console bell."""<br>    print('\a', end='', flush=True)<br><br># ---------- main ----------<br>def main():<br>    p = argparse.ArgumentParser(description="Desktop break reminder")<br>    p.add_argument('-i', '--interval', default='60m',<br>                   help='Time between reminders (e.g. 20m, 2h, 45s).')<br>    p.add_argument('-c', '--count', type=int, default=0,<br>                   help='Number of reminders then exit (0 = unlimited).')<br>    p.add_argument('-t', '--title', default='ALERT!!!',<br>                   help='Notification title text.')<br>    p.add_argument('-m', '--message',<br>                   help='Notification body; omit → random tip.')<br>    args = p.parse_args()<br><br>    wait = parse_interval(args.interval)<br>    remaining = args.count<br><br>    print(f"[{dt.datetime.now():%H:%M:%S}] Timer started – every "<br>          f"{wait//60 if wait>=60 else wait} "<br>          f"{'min' if wait>=60 else 'sec'} "<br>          f"({ '∞' if remaining==0 else remaining} alerts). Ctrl-C to quit.")<br><br>    try:<br>        while remaining != -1:            # -1 means we hit the limit<br>            body = args.message or random.choice(_TIPS)<br>            notification.notify(title=args.title,<br>                                message=body,<br>                                app_name="Break Timer")<br>            beep()<br>            print(f"[{dt.datetime.now():%H:%M:%S}] Notified: {body}")<br><br>            if remaining > 0:<br>                remaining -= 1<br>                if remaining == 0:<br>                    break<br>            time.sleep(wait)<br>    except KeyboardInterrupt:<br>        print("\nStopped by user. Have a healthy day! &#x1f44b;")<br>        sys.exit(0)<br><br>if __name__ == "__main__":<br>    main()<br></code></pre><h2 class="wp-block-heading">Running the upgraded version</h2><pre class="wp-block-preformatted"><code>install plyer           # one-time<br>python break_timer.py -i 45m                 # ping every 45 min<br>python break_timer.py -i 20m -c 6            # six pings then exit<br>python break_timer.py -i 90s -t "Hydrate" \<br>       -m "Sip some water &#x1f6b0;"                 # custom text<br></code></pre><h3 class="wp-block-heading">Quick flag reference</h3><figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Flag</th><th>Example</th><th>Purpose</th></tr></thead><tbody><tr><td><code>-i</code>, <code>--interval</code></td><td><code>-i 90s</code></td><td>How often to remind (supports s/m/h suffix).</td></tr><tr><td><code>-c</code>, <code>--count</code></td><td><code>-c 4</code></td><td>Quit after N reminders.</td></tr><tr><td><code>-t</code>, <code>--title</code></td><td><code>-t "Hydrate"</code></td><td>Notification headline.</td></tr><tr><td><code>-m</code>, <code>--message</code></td><td><code>-m "Drink water"</code></td><td>Body text (skip for a random tip).</td></tr></tbody></table></figure><h2 class="wp-block-heading">Stretch goals I’m tinkering with</h2><ol class="wp-block-list"><li><strong>System-tray icon with pause/resume</strong> for meetings.</li>
  55.  
  56. <li><strong>Work-hours window</strong> so it only nags 09:00-18:00.</li>
  57.  
  58. <li><strong>CSV/JSON logging</strong> to track how often I <em>actually</em> moved.</li>
  59.  
  60. <li><strong>Tkinter GUI</strong> so colleagues can set it up without CLI knowledge.</li>
  61.  
  62. <li><strong>GIF micro-exercises</strong>—imagine a shoulder-roll animation popping up.</li>
  63.  
  64. <li><strong>Voice alert</strong> via <code>pyttsx3</code> for the perpetually alt-tabbed.</li></ol><h2 class="wp-block-heading">Final thought</h2><p>Writing this tiny utility reminded me <em>why I love Python</em>:<br><strong>a couple of imports + the right library = instant quality-of-life boost.</strong></p><p>Feel free to fork, tweak, and ship your own flavour. Just remember: the best code you’ll ever write might be the one that literally tells you to stop coding for a minute.</p>]]></content:encoded>
  65. <wfw:commentRss>https://fsiblog.io/how-to-build-a-tiny-python-app-that-reminds-me-to-take-breaks/feed/</wfw:commentRss>
  66. <slash:comments>0</slash:comments>
  67. <post-id xmlns="com-wordpress:feed-additions:1">2188</post-id> </item>
  68. <item>
  69. <title>How I Built a Flexible CAPTCHA Generator &#038; Verifier Using Python</title>
  70. <link>https://fsiblog.io/how-i-built-a-flexible-captcha-generator-verifier-using-python/</link>
  71. <comments>https://fsiblog.io/how-i-built-a-flexible-captcha-generator-verifier-using-python/#respond</comments>
  72. <dc:creator><![CDATA[Daniyal Ahmed]]></dc:creator>
  73. <pubDate>Tue, 29 Apr 2025 05:15:04 +0000</pubDate>
  74. <category><![CDATA[Python]]></category>
  75. <category><![CDATA[Built a Flexible CAPTCHA Generator & Verifier Using Python]]></category>
  76. <category><![CDATA[Flexible CAPTCHA Generator & Verifier Using Python]]></category>
  77. <guid isPermaLink="false">https://fsiblog.io/?p=2185</guid>
  78.  
  79. <description><![CDATA[I’ve always enjoyed adding little “mini-projects” to my tool belt especially ones that combine clean code with a bit of visual flair. Recently I needed a dead-simple CAPTCHA for a hobby site, so I reached for the underrated captcha Python library and ended up writing a tiny CLI that now lives in my dotfiles. Deep-dive [&#8230;]]]></description>
  80. <content:encoded><![CDATA[<p>I’ve always enjoyed adding little “mini-projects” to my tool belt especially ones that combine clean code with a bit of visual flair. Recently I needed a dead-simple CAPTCHA for a hobby site, so I reached for the underrated <code>captcha</code> Python library and ended up writing a tiny CLI that now lives in my dotfiles.</p><ul class="wp-block-list"><li><strong>Walk through the original 30-line snippet line-by-line</strong> so you can see <em>exactly</em> what every import and call does.</li>
  81.  
  82. <li><strong>Show you my extended, production-ready version</strong>: command-line switches, automatic verification, custom fonts/colours/noise, in-memory handling, and batch mode everything I wished the demo had on day one.</li>
  83.  
  84. <li><strong>Share next-step ideas</strong> (FastAPI micro-service, audio CAPTCHAs, adversarial OCR tests) and wrap up with a few lessons learned.</li></ul><h2 class="wp-block-heading">Deep-dive into the “Hello World” CAPTCHA</h2><p>Before I rewrote anything, I wanted to know where every byte came from. Here’s the tiniest viable script, followed by a table-style breakdown:</p><pre class="wp-block-preformatted"><code>from PIL import Image<br>import random, string<br><br><br>def generate_captcha_text(length: int = 6) -> str:<br>    chars = string.ascii_letters + string.digits<br>    return ''.join(random.choices(chars, k=length))<br><br><br>def generate_captcha_image(captcha_text: str,<br>                           image_width: int = 300) -> str:<br>    image = ImageCaptcha(width=image_width)<br>    file_name = f"{captcha_text}.png"<br>    image.write(captcha_text, file_name)<br>    return file_name<br><br><br>if __name__ == "__main__":<br>    text = generate_captcha_text()<br>    file_path = generate_captcha_image(text)<br><br>    print(f"Generated CAPTCHA text: {text}")<br>    Image.open(file_path).show()<br></code></pre><figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>#</th><th>Code</th><th>What <em>really</em> happens</th></tr></thead><tbody><tr><td>1</td><td><code>from captcha.image import ImageCaptcha</code></td><td>Pulls in the renderer that bends, warps, and sprinkles noise on text simple OCR dies instantly.</td></tr><tr><td>2</td><td><code>from PIL import Image</code></td><td>Pillow lets me open/preview the PNG that <code>ImageCaptcha.write()</code> just saved.</td></tr><tr><td>3</td><td><code>import random, string</code></td><td>Core helpers: <code>random.choices()</code> (sampling with replacement) and <code>string.ascii_letters + string.digits</code> (62-char pool).</td></tr><tr><td>4-9</td><td><code>generate_captcha_text()</code></td><td>1) Builds the pool. 2) Picks <code>length</code> symbols uniformly. 3) Returns a contiguous string such as <code>A9cV4K</code>.</td></tr><tr><td>11-19</td><td><code>generate_captcha_image()</code></td><td>1) Instantiates the renderer (I can also tweak height/fonts/colours/noise).\ 2) <code>write()</code> rasterises &amp; <strong>saves</strong> the PNG.</td></tr><tr><td>21-31</td><td><code>__main__</code> guard</td><td>Random text → image → debug print. Finally <code>Image.open().show()</code> asks my OS to preview the file.</td></tr></tbody></table></figure><h3 class="wp-block-heading">Fast tweaks</h3><figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>What I changed</th><th>One-liner</th></tr></thead><tbody><tr><td>8-char puzzle</td><td><code>generate_captcha_text(8)</code></td></tr><tr><td>Custom size/font</td><td><code>ImageCaptcha(width=280, height=90, fonts=['./Roboto-Bold.ttf'])</code></td></tr><tr><td>Black on white, 40 % noise</td><td><code>ImageCaptcha(color='black', background='white', noise_level=0.4)</code></td></tr></tbody></table></figure><h2 class="wp-block-heading">Level-up: the <strong><code>captcha_tool.py</code></strong> CLI</h2><p>One-offs are fun, but I wanted a Swiss-Army knife:</p><ul class="wp-block-list"><li><strong>Flags</strong> so I can whip up 5 CAPTCHAs in one go (<code>--count 5</code>).</li>
  85.  
  86. <li><strong>Verification loop</strong> when I’m demoing to friends (<code>--verify</code>).</li>
  87.  
  88. <li><strong>Memory-only mode</strong> for server responses no temp files (<code>--nodisk</code>).</li>
  89.  
  90. <li><strong>House-keeping</strong> so PNGs older than <em>n</em> minutes vanish automatically.</li>
  91.  
  92. <li><strong>Colour / font / noise knobs</strong> because brand guidelines are real.</li></ul><p>Below is the trimmed-down version (full gist at the end). Copy-paste, rename to <code>captcha_tool.py</code>, and you’re off.</p><pre class="wp-block-preformatted">\<code>captcha_tool.py<br>Generate and optionally verify CAPTCHA challenges from the command line.<br>"""<br><br>import argparse, io, random, string, sys<br>from datetime import datetime, timedelta<br>from pathlib import Path<br><br>from captcha.image import ImageCaptcha<br>from PIL import Image<br><br><br># ---------- helpers ---------- #<br>def random_text(length: int) -> str:<br>    pool = string.ascii_letters + string.digits<br>    return "".join(random.choices(pool, k=length))<br><br><br>def draw_captcha(text: str,<br>                 width: int = 300,<br>                 height: int = 100,<br>                 color: str = "black",<br>                 background: str = "white",<br>                 noise: float = 0.4,<br>                 fonts: list[str] | None = None,<br>                 to_disk: bool = True) -> tuple[str, bytes | None]:<br>    gen = ImageCaptcha(width=width, height=height,<br>                       fonts=fonts,<br>                       color=color, background=background,<br>                       noise_level=noise)<br>    if to_disk:<br>        name = f"{datetime.utcnow().timestamp()}_{text}.png"<br>        gen.write(text, name)<br>        return name, None<br>    buf = io.BytesIO()<br>    gen.write(text, buf)<br>    return f"mem://{text}", buf.getvalue()<br><br><br># ---------- CLI entry-point ---------- #<br>def main() -> None:<br>    p = argparse.ArgumentParser(description="Quick CAPTCHA generator")<br>    p.add_argument("--len", type=int, default=6, help="char length")<br>    p.add_argument("--count", type=int, default=1, help="# captchas")<br>    p.add_argument("--verify", action="store_true", help="ask user to solve")<br>    p.add_argument("--nodisk", action="store_true", help="keep in memory")<br>    p.add_argument("--clean-after", type=int, default=15,<br>                   help="delete PNGs older than X minutes")<br>    args = p.parse_args()<br><br>    challenges: list[tuple[str, str]] = []<br>    for _ in range(args.count):<br>        ans = random_text(args.len)<br>        fname, _ = draw_captcha(ans, to_disk=not args.nodisk)<br>        print(f"[+] CAPTCHA ready: {fname}")<br>        challenges.append((ans, fname))<br><br>    if args.verify:<br>        for ans, fname in challenges:<br>            if not args.nodisk:<br>                Image.open(fname).show()<br>            guess = input("Text you see → ").strip()<br>            print("&#x2705;  Correct!\n" if guess == ans else f"&#x274c;  Nope (was {ans})\n")<br><br>    if not args.nodisk and args.clean_after > 0:<br>        cut = datetime.utcnow() - timedelta(minutes=args.clean_after)<br>        for png in Path(".").glob("*.png"):<br>            if datetime.utcfromtimestamp(png.stat().st_mtime) &lt; cut:<br>                png.unlink(missing_ok=True)<br><br><br>if __name__ == "__main__":<br>    main()<br></code></pre><h3 class="wp-block-heading">Quick demos</h3><figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Skill I practise</th><th>Command I run</th></tr></thead><tbody><tr><td>CLI flag parsing</td><td><code>python captcha_tool.py --len 8 --count 5</code></td></tr><tr><td>User validation</td><td><code>python captcha_tool.py --verify</code></td></tr><tr><td>Memory-only flow</td><td><code>python captcha_tool.py --nodisk</code></td></tr><tr><td>Auto cleanup</td><td><code>python captcha_tool.py --clean-after 1</code></td></tr><tr><td>Custom styling</td><td>Edit <code>draw_captcha()</code> and crank noise / fonts</td></tr></tbody></table></figure><h2 class="wp-block-heading">Where I’ll take it next</h2><ul class="wp-block-list"><li><strong>FastAPI endpoint</strong> – <code>/captcha/new</code> returns base64 PNG + token, <code>/captcha/verify</code> checks answer and TTL.</li>
  93.  
  94. <li><strong>Redis store</strong> – token → answer → expiry, so I never keep secrets in RAM longer than necessary.</li>
  95.  
  96. <li><strong>Audio fallback</strong> – <code>captcha.audio.AudioCaptcha</code> for accessibility compliance.</li>
  97.  
  98. <li><strong>Adversarial OCR tests</strong> – pipe PNGs into Tesseract, tighten noise until solve-rate &lt; 1 %.</li>
  99.  
  100. <li><strong>Vue widget</strong> – tiny component that fetches fresh images with <code>fetch()</code> and updates view in-place.</li></ul><h2 class="wp-block-heading">Final thought</h2><p>I went in needing a single throw-away CAPTCHA; I came out with a reusable CLI and a blueprint for a micro-service. <strong>The lesson?</strong> Even the tiniest scripts are opportunities to practise <em>clean switches</em>, <em>separation of concerns</em>, and <em>automated clean-up</em>. Next time you’re about to toss a “one-liner” into production, pause, add flags, and you might surprise yourself with how far that extra 30 minutes takes you.</p>]]></content:encoded>
  101. <wfw:commentRss>https://fsiblog.io/how-i-built-a-flexible-captcha-generator-verifier-using-python/feed/</wfw:commentRss>
  102. <slash:comments>0</slash:comments>
  103. <post-id xmlns="com-wordpress:feed-additions:1">2185</post-id> </item>
  104. <item>
  105. <title>How to Fix Application Error in Twilio Voice Call with Django/Python?</title>
  106. <link>https://fsiblog.io/how-to-fix-application-error-in-twilio-voice-call-with-django-python/</link>
  107. <comments>https://fsiblog.io/how-to-fix-application-error-in-twilio-voice-call-with-django-python/#respond</comments>
  108. <dc:creator><![CDATA[Daniyal Ahmed]]></dc:creator>
  109. <pubDate>Mon, 28 Apr 2025 06:29:23 +0000</pubDate>
  110. <category><![CDATA[Python]]></category>
  111. <category><![CDATA[Application Error in Twilio Voice Call with Django/Python?]]></category>
  112. <category><![CDATA[Fix Application Error in Twilio Voice Call with Django/Python?]]></category>
  113. <guid isPermaLink="false">https://fsiblog.io/?p=2182</guid>
  114.  
  115. <description><![CDATA[I’m excited to share my recent experience integrating Twilio Voice into a Django application to deliver one-time passwords (OTPs) via phone calls. When I first set up my /outbound/ endpoint, it rendered valid TwiML XML perfectly in the browser. However, triggering a call through Twilio resulted in a frustrating “Sorry, an application error has occurred” [&#8230;]]]></description>
  116. <content:encoded><![CDATA[<p>I’m excited to share my recent experience integrating Twilio Voice into a Django application to deliver one-time passwords (OTPs) via phone calls. When I first set up my <code>/outbound/</code> endpoint, it rendered valid TwiML XML perfectly in the browser. However, triggering a call through Twilio resulted in a frustrating “Sorry, an application error has occurred” message.</p><ol class="wp-block-list"><li>The original code that led to the error</li>
  117.  
  118. <li>My diagnosis of what went wrong</li>
  119.  
  120. <li>A corrected implementation that works</li>
  121.  
  122. <li>Extra “practice” enhancements to deepen the integration</li></ol><h2 class="wp-block-heading">Error Code</h2><p>Here’s the initial view code I wrote in <strong>views.py</strong>: &lt;details&gt; &lt;summary&gt;&lt;strong&gt;views.py (original)&lt;/strong&gt;&lt;/summary&gt;</p><pre class="wp-block-preformatted"><code>django.conf import settings<br>from django.http import HttpResponse<br>from twilio.rest import TwilioRestClient  # legacy import<br>import twilio.twiml<br><br>def voice_call(otp, mobile_no):<br>    client = TwilioRestClient(settings.ACCOUNT_SID, settings.AUTH_TOKEN)<br>    client.calls.create(<br>        from_=settings.OTP_FROM_NUMBER,<br>        to=mobile_no,<br>        url='http://localhost:8000/outbound/',<br>        method='POST'<br>    )<br><br>def outbound(self):<br>    response = twiml.Response()<br>    response.say("Thank you for contacting our department", voice='alice')<br>    return HttpResponse(response, content_type="application/xml")<br></code></pre><p>&lt;/details&gt;</p><p>This looked straightforward: trigger a call to <code>mobile_no</code> and have Twilio POST to my <code>/outbound/</code> endpoint, which returns TwiML telling it to speak a message.</p><h2 class="wp-block-heading">Define “Application Error”</h2><p>After some investigation, I identified three root issues:</p><ol class="wp-block-list"><li><strong>Incorrect view signature</strong><ul class="wp-block-list"><li>Django views must accept a <code>request</code> object as their first parameter. Defining <code>outbound(self)</code> meant Django couldn’t match the signature, resulting in an internal server error (HTTP 500).</li></ul></li>
  123.  
  124. <li><strong>Legacy Twilio client import</strong><ul class="wp-block-list"><li>Using <code>TwilioRestClient</code> is deprecated. The modern <code>twilio.rest.Client</code> class is more reliable and up to date.</li></ul></li>
  125.  
  126. <li><strong>Localhost not publicly accessible</strong><ul class="wp-block-list"><li>When Twilio’s servers attempt to fetch your TwiML at <code>http://localhost:8000/outbound/</code>, they cannot reach your local machine. Twilio requires a publicly accessible URL (for example, via an ngrok tunnel or your own domain).</li></ul></li></ol><h2 class="wp-block-heading">Correct Implementation</h2><p>Here’s the revised <strong>views.py</strong> that addresses all three problems: &lt;details&gt; &lt;summary&gt;&lt;strong&gt;views.py (fixed)&lt;/strong&gt;&lt;/summary&gt;</p><pre class="wp-block-preformatted"><code>django.conf import settings<br>from django.http import HttpResponse<br>from django.views.decorators.csrf import csrf_exempt<br>from twilio.rest import Client<br>from twilio.twiml.voice_response import VoiceResponse<br><br>def voice_call(request, otp, mobile_no):<br>    """<br>    Initiates a Twilio voice call to deliver an OTP.<br>    """<br>    client = Client(settings.ACCOUNT_SID, settings.AUTH_TOKEN)<br><br>    # Use a publicly accessible URL (e.g., via ngrok)<br>    twiml_url = settings.TWILIO_TWIML_URL  # e.g. 'https://abcd1234.ngrok.io/outbound/'<br><br>    client.calls.create(<br>        from_=settings.OTP_FROM_NUMBER,<br>        to=mobile_no,<br>        url=twiml_url,<br>        method='POST'<br>    )<br>    return HttpResponse("Call initiated", status=202)<br><br>@csrf_exempt<br>def outbound(request):<br>    """<br>    Responds to Twilio’s webhook with TwiML instructions.<br>    """<br>    resp = VoiceResponse()<br>    resp.say("Thank you for contacting our department. Your OTP is:", voice='alice')<br><br>    # Optionally inject the OTP dynamically via query string or storage<br>    otp = request.GET.get('otp', 'unknown')<br>    resp.say(otp, voice='alice')<br><br>    return HttpResponse(str(resp), content_type="application/xml")<br></code></pre><p>&lt;/details&gt;</p><p><strong>Key fixes explained:</strong></p><ul class="wp-block-list"><li><strong><code>outbound(request)</code></strong>: Replaced <code>self</code> with <code>request</code> so Django can invoke it properly.</li>
  127.  
  128. <li><strong><code>Client</code></strong>: Swapped out the deprecated <code>TwilioRestClient</code> for the modern <code>Client</code> class.</li>
  129.  
  130. <li><strong><code>@csrf_exempt</code></strong>: Added to allow Twilio’s POST without a CSRF token.</li>
  131.  
  132. <li><strong>Public URL</strong>: Set <code>TWILIO_TWIML_URL</code> in settings (for example, an ngrok tunnel) so Twilio can reach your TwiML.</li></ul><h2 class="wp-block-heading">Additional “Practice” Functionality</h2><p>Once you have the basics working, you can supercharge your integration. Here are a few ideas to practice:</p><h3 class="wp-block-heading">Error Handling &amp; Logging</h3><pre class="wp-block-preformatted"><code><br>    client.calls.create(…)<br>except Exception as e:<br>    logger.error(f"Twilio call failed: {e}")<br>    return HttpResponse("Error initiating call", status=500)<br></code></pre><h3 class="wp-block-heading">Gather User Input</h3><p>Let callers press a digit and handle their response:</p><pre class="wp-block-preformatted"><code>twilio.twiml.voice_response import Gather<br><br>@csrf_exempt<br>def outbound(request):<br>    resp = VoiceResponse()<br>    gather = Gather(num_digits=1, action='/gather-response/', method='POST')<br>    gather.say("Press 1 to confirm receipt of the OTP.", voice='alice')<br>    resp.append(gather)<br>    resp.redirect('/outbound/')  # repeat if no input<br>    return HttpResponse(str(resp), content_type="application/xml")<br></code></pre><h3 class="wp-block-heading">Play an Audio File</h3><pre class="wp-block-preformatted"><code>.play(url="https://example.com/hold-music.mp3")</code></pre><h3 class="wp-block-heading">Record the Call</h3><p>Tell Twilio to record the conversation:</p><pre class="wp-block-preformatted"><code>.calls.create(…, record=True)</code></pre><h3 class="wp-block-heading">Dynamic TwiML Generation</h3><p>Store the OTP in your database or session, then look it up in <code>outbound()</code> instead of passing it in the URL.</p><h2 class="wp-block-heading">Final Thoughts</h2><p>By correcting my view signature, updating to the modern Twilio Python client, and exposing a public TwiML URL, I eliminated the mysterious “application error.” From here, you can layer on advanced TwiML features,user input, recordings, audio playback, and more to build an interactive voice experience.</p>]]></content:encoded>
  133. <wfw:commentRss>https://fsiblog.io/how-to-fix-application-error-in-twilio-voice-call-with-django-python/feed/</wfw:commentRss>
  134. <slash:comments>0</slash:comments>
  135. <enclosure url="https://example.com/hold-music.mp3" length="1256" type="audio/mpeg" />
  136.  
  137. <post-id xmlns="com-wordpress:feed-additions:1">2182</post-id> </item>
  138. <item>
  139. <title>How to Fix Python Application Giving Error Deployed Through Docker</title>
  140. <link>https://fsiblog.io/how-to-fix-python-application-giving-error-deployed-through-docker/</link>
  141. <comments>https://fsiblog.io/how-to-fix-python-application-giving-error-deployed-through-docker/#respond</comments>
  142. <dc:creator><![CDATA[Daniyal Ahmed]]></dc:creator>
  143. <pubDate>Mon, 28 Apr 2025 06:09:18 +0000</pubDate>
  144. <category><![CDATA[Python]]></category>
  145. <category><![CDATA[Fix Python Application Giving Error Deployed Through Docker]]></category>
  146. <category><![CDATA[Python Application Giving Error Deployed Through Docker]]></category>
  147. <guid isPermaLink="false">https://fsiblog.io/?p=2178</guid>
  148.  
  149. <description><![CDATA[I’m excited to share a little troubleshooting journey I recently went through while deploying a Python web application inside Docker. If you’ve ever felt confident that “Docker makes everything just work” only to be tripped up by a bizarre bind error you’re in good company. Dockerfile &#38; Application Code I started with the most stripped-down [&#8230;]]]></description>
  150. <content:encoded><![CDATA[<p>I’m excited to share a little troubleshooting journey I recently went through while deploying a Python web application inside Docker. If you’ve ever felt confident that “Docker makes everything just work” only to be tripped up by a bizarre bind error you’re in good company.</p><ol class="wp-block-list"><li>The minimal Dockerfile and <code>main.py</code> that reproduce the problem.</li>
  151.  
  152. <li>A deep dive into the error itself and why it happens.</li>
  153.  
  154. <li>The simple fix that gets your containerized Sanic server back online.</li>
  155.  
  156. <li>A few “practice” enhancements health checks, environment-driven configuration, and basic logging to turn this demo into a sturdier template you can reuse.</li></ol><h2 class="wp-block-heading">Dockerfile &amp; Application Code</h2><p>I started with the most stripped-down setup I could imagine. &lt;details&gt; &lt;summary&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;/summary&gt;</p><pre class="wp-block-preformatted"><code>python:3.8<br><br>WORKDIR /usr/src/app<br><br># Install dependencies<br>COPY requirements.txt ./<br>RUN pip install --no-cache-dir -r requirements.txt<br><br># Copy application code<br>COPY . .<br><br>EXPOSE 8000<br><br># By default, this invokes Sanic's CLI,<br># which binds to ::1 (IPv6 localhost) unless overridden.<br>CMD ["python3", "apps/main.py", "start", "--config", "config.yml"]<br></code></pre><p>&lt;/details&gt; &lt;details&gt; &lt;summary&gt;&lt;strong&gt;apps/main.py&lt;/strong&gt;&lt;/summary&gt;</p><pre class="wp-block-preformatted"><code># apps/main.py<br><br>from sanic import Sanic<br>from sanic.response import json<br><br>app = Sanic("DemoApp")<br><br>@app.route("/")<br>async def home(request):<br>    return json({"message": "Hello from inside Docker!"})<br><br>if __name__ == "__main__":<br>    # Sanic.create().run() without args binds to IPv6 localhost (::1) by default.<br>    Sanic.create(app).run(<br>        host="::1",<br>        port=8000,<br>        debug=True,<br>        autoreload=True,<br>    )<br></code></pre><h3 class="wp-block-heading">Error Code</h3><p>When I built and ran this container, I was expecting to see my “Hello from inside Docker!” message. Instead, it crashed immediately with:</p><pre class="wp-block-preformatted"><code>: [Errno 99] error while attempting to bind on address ('::1', 8000, 0, 0):<br>    cannot assign requested address<br>[INFO] Server Stopped</code></pre><h2 class="wp-block-heading">Under the Hood: What’s Really Going On</h2><p>At first glance, “Errno 99” might feel impenetrable, but here’s the core of the issue:</p><ul class="wp-block-list"><li><strong>Sanic’s default host</strong> (when you don’t explicitly pass <code>--host</code> on the CLI) is <code>::1</code> the IPv6 loopback address.</li>
  157.  
  158. <li><strong>Docker containers</strong>, out of the box, don’t always configure an IPv6 loopback interface. Only the IPv4 loopback (<code>127.0.0.1</code>) is guaranteed.</li>
  159.  
  160. <li>As a result, when Sanic calls <code>bind("::1", 8000)</code>, the kernel says, “I have no idea what <code>::1</code> is here,” and refuses to create the socket.</li></ul><p>Because the server never binds successfully, the container’s main process exits and Docker stops the container.</p><h2 class="wp-block-heading">The Fix: Bind to <code>0.0.0.0</code></h2><p>The solution is straightforward: tell Sanic to listen on IPv4’s “all interfaces” address <code>0.0.0.0</code>. This ensures it will bind to the container’s network interface that’s mapped to the host.</p><h3 class="wp-block-heading">Update <code>main.py</code> Directly</h3><pre class="wp-block-preformatted"><code>-    Sanic.create(app).run(<br>-        host="::1",<br>+    Sanic.create(app).run(<br>+        host="0.0.0.0",       # bind to all IPv4 interfaces<br>         port=8000,<br>         debug=True,<br>         autoreload=True,<br>     )</code></pre><h3 class="wp-block-heading">Override via the Docker CMD</h3><p>Alternatively, you can leave your code untouched and pass the bind flags in the Dockerfile:</p><pre class="wp-block-preformatted"><code>-CMD ["python3", "apps/main.py", "start", "--config", "config.yml"]<br>+CMD [<br>+  "python3", "apps/main.py", "start",<br>+  "--host", "0.0.0.0",<br>+  "--port", "8000",<br>+  "--config", "config.yml"<br>+]<br></code></pre><p>Then rebuild and run:</p><pre class="wp-block-preformatted"><code>build -t demo-app .<br>docker run -p 8000:8000 demo-app<br></code></pre><p>You should now see your Sanic server come up cleanly, and you’ll be able to <code>curl http://localhost:8000/</code> to verify the JSON response.</p><h2 class="wp-block-heading">Practice Enhancements</h2><p>Once the basic binding issue is solved, I like to add a few small improvements to turn this into a more reusable boilerplate.</p><h3 class="wp-block-heading">Environment Driven Configuration</h3><p>Hard coding host, port, and debug flags can be inflexible. Instead, read them from environment variables:</p><pre class="wp-block-preformatted"><code># apps/main.py<br><br>import os<br>from sanic import Sanic<br>from sanic.response import json<br><br>app = Sanic("DemoApp")<br><br>@app.route("/")<br>async def home(request):<br>    return json({"message": "Hello from inside Docker!"})<br><br>@app.route("/health")<br>async def health(request):<br>    return json({"status": "OK"})<br><br>if __name__ == "__main__":<br>    host = os.getenv("APP_HOST", "0.0.0.0")<br>    port = int(os.getenv("APP_PORT", 8000))<br>    debug = os.getenv("SANIC_DEBUG", "false").lower() == "true"<br><br>    Sanic.create(app).run(<br>        host=host,<br>        port=port,<br>        debug=debug,<br>        autoreload=debug,<br>    )<br></code></pre><p>And in the Dockerfile:</p><pre class="wp-block-preformatted"><code>APP_HOST=0.0.0.0<br>ENV APP_PORT=8000<br>ENV SANIC_DEBUG=true<br><br>CMD ["python3", "apps/main.py", "start"]<br></code></pre><p>Now you can tweak behavior at deploy time without rebuilding your image.</p><h3 class="wp-block-heading">Health-Check Endpoint</h3><p>I added a <code>GET /health</code> route so that Docker or Kubernetes can periodically poll it:</p><pre class="wp-block-preformatted"><code>@app.route("/health")<br>async def health(request):<br>    return json({"status": "OK"})<br></code></pre><p>This helps you wire in readiness and liveness probes in orchestrators.</p><h3 class="wp-block-heading">Basic Logging</h3><p>Sanic includes a built-in logger. A quick setup lets you log inside your routes:</p><pre class="wp-block-preformatted"><code>logging<br><br>log = logging.getLogger("sanic.root")<br>log.setLevel(logging.INFO)<br><br>@app.route("/items/&lt;item_id>")<br>async def get_item(request, item_id):<br>    log.info(f"Fetching item {item_id}")<br>    # … pretend we fetch from a database …<br>    return json({"item_id": item_id})<br></code></pre><p>With logs going to <code>stdout</code>, you can aggregate and inspect them in production.</p><h2 class="wp-block-heading">Final Thought</h2><p>I’m continually reminded that containerizing an application can surface unexpected assumptions like default IPv6 binding that never come up in local development. By explicitly binding to <code>0.0.0.0</code>, introducing environment-driven configuration, health-check endpoints, and structured logging, I’ve turned a minimal repro into a flexible starting point you can drop into almost any Python-in-Docker project.</p>]]></content:encoded>
  161. <wfw:commentRss>https://fsiblog.io/how-to-fix-python-application-giving-error-deployed-through-docker/feed/</wfw:commentRss>
  162. <slash:comments>0</slash:comments>
  163. <post-id xmlns="com-wordpress:feed-additions:1">2178</post-id> </item>
  164. <item>
  165. <title>How to Solve Error While Installing Ruby Using RVM</title>
  166. <link>https://fsiblog.io/how-to-solve-error-while-installing-ruby-using-rvm/</link>
  167. <comments>https://fsiblog.io/how-to-solve-error-while-installing-ruby-using-rvm/#respond</comments>
  168. <dc:creator><![CDATA[Shaheen Ullah]]></dc:creator>
  169. <pubDate>Sat, 26 Apr 2025 06:57:08 +0000</pubDate>
  170. <category><![CDATA[Ruby]]></category>
  171. <category><![CDATA[Error While Installing Ruby Using RVM]]></category>
  172. <category><![CDATA[Solve Error While Installing Ruby Using RVM]]></category>
  173. <guid isPermaLink="false">https://fsiblog.io/?p=2175</guid>
  174.  
  175. <description><![CDATA[I’ve been down the rabbit hole of Ruby installations more times than I care to admit. When I first tried to install Ruby 1.9.3 via RVM on Ubuntu, I hit this brick wall: $ rvm install 1.9.3Searching for binary rubies, this might take some time.Checking requirements for ubuntu.Installing requirements for ubuntu.Updating system..................................................................................................Error running 'requirements_debian_update_system ruby-1.9.3-p448',please [&#8230;]]]></description>
  176. <content:encoded><![CDATA[<p>I’ve been down the rabbit hole of Ruby installations more times than I care to admit. When I first tried to install Ruby 1.9.3 via RVM on Ubuntu, I hit this brick wall:</p><pre class="wp-block-preformatted"><code>$ rvm install 1.9.3<br>Searching for binary rubies, this might take some time.<br>Checking requirements for ubuntu.<br>Installing requirements for ubuntu.<br>Updating system..................................................................................................<br>Error running 'requirements_debian_update_system ruby-1.9.3-p448',<br>please read /home/troy/.rvm/log/1379872584_ruby-1.9.3-p448/update_system.log<br>Requirements installation failed with status: 100.<br></code></pre><p>I know that staring at “status: 100” in your terminal can feel like a dead end. I’ll walk you through how I turned that failure into a reproducible, robust installation script complete with error handling, clear logs, and extra practice steps so you can level up your Bash and RVM skills.</p><h2 class="wp-block-heading">Why Automate Ruby Installation?</h2><p>Manually typing commands each time is error-prone. A script lets me:</p><ul class="wp-block-list"><li><strong>Capture errors</strong> immediately and log details.</li>
  177.  
  178. <li><strong>Retry flaky operations</strong> without starting over.</li>
  179.  
  180. <li><strong>Share a reproducible recipe</strong> across projects and teammates.</li></ul><p>Ready? Let’s dive in.</p><h3 class="wp-block-heading">The Installation Script</h3><p>Create a file <code>install_ruby.sh</code> in your home directory, then make it executable:</p><pre class="wp-block-preformatted"><code>chmod +x ~/install_ruby.sh<br></code></pre><p>Paste this content into it:</p><pre class="wp-block-preformatted"><code>#!/usr/bin/env bash<br><br># install_ruby.sh<br># A simple wrapper to install Ruby via RVM with error detection<br><br>RUBY_VERSION="1.9.3"<br>LOGFILE="$HOME/rvm_install_$(date +%Y%m%d_%H%M%S).log"<br><br>echo "Starting Ruby $RUBY_VERSION installation at $(date)" | tee "$LOGFILE"<br><br># 1. Update and install system requirements<br>echo "Step 1: Installing prerequisites…" | tee -a "$LOGFILE"<br>if sudo apt-get update &amp;&amp; \<br>   sudo apt-get install -y curl gnupg build-essential \<br>      libssl-dev libreadline-dev zlib1g-dev; then<br>  echo "&#x2714; Prerequisites installed" | tee -a "$LOGFILE"<br>else<br>  echo "&#x2716; Failed to install prerequisites" | tee -a "$LOGFILE"<br>  exit 1<br>fi<br><br># 2. Import RVM GPG keys<br>echo "Step 2: Importing RVM GPG keys…" | tee -a "$LOGFILE"<br>command -v gpg >/dev/null || sudo apt-get install -y gnupg2<br>gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys \<br>    409B6B1796C275462A1703113804BB82D39DC0E3 \<br>    7D2BAF1CF37B13E2069D6956105BD0E739499BDB \<br>  &amp;>> "$LOGFILE" || { echo "&#x2716; GPG import failed" | tee -a "$LOGFILE"; exit 2; }<br><br># 3. Install or reload RVM<br>echo "Step 3: Installing/reloading RVM…" | tee -a "$LOGFILE"<br>if ! command -v rvm >/dev/null; then<br>  \curl -sSL https://get.rvm.io | bash -s stable &amp;>> "$LOGFILE"<br>  source "$HOME/.rvm/scripts/rvm"<br>else<br>  echo "&#x2714; RVM already installed" | tee -a "$LOGFILE"<br>  source "$HOME/.rvm/scripts/rvm"<br>fi<br><br># 4. Install Ruby<br>echo "Step 4: Installing Ruby $RUBY_VERSION…" | tee -a "$LOGFILE"<br>if rvm install "$RUBY_VERSION" &amp;>> "$LOGFILE"; then<br>  echo "&#x2714; Ruby installed successfully" | tee -a "$LOGFILE"<br>else<br>  code=$?<br>  echo "&#x2716; Ruby install failed with status $code" | tee -a "$LOGFILE"<br>  echo "Check logs: $LOGFILE and ~/.rvm/log/" | tee -a "$LOGFILE"<br>  exit $code<br>fi<br><br># 5. Set default Ruby and verify<br>echo "Step 5: Setting default Ruby…" | tee -a "$LOGFILE"<br>rvm --default use "$RUBY_VERSION" &amp;>> "$LOGFILE"<br>ruby -v | tee -a "$LOGFILE"<br><br>echo "Installation completed at $(date)" | tee -a "$LOGFILE"<br></code></pre><p>Save and run:</p><pre class="wp-block-preformatted"><code>~/install_ruby.sh</code></pre><h2 class="wp-block-heading">What “status: 100” Really Means</h2><p>Whenever RVM exits with <strong>100</strong>, it usually signals that <strong>dependency installation failed</strong> during the <code>requirements_debian_update_system</code> phase. In plain terms, <code>apt-get install</code> hit a snag—missing packages, network hiccups, or a locked dpkg database. The detailed reason lives in:</p><pre class="wp-block-preformatted"><code>~/.rvm/log/&lt;timestamp>/update_system.log</code></pre><p>Peek at that log to pinpoint the broken dependency.</p><h2 class="wp-block-heading">How the Script Works</h2><ol class="wp-block-list"><li><strong>Prerequisite Installation</strong><br>I update <code>apt</code> and install libraries (OpenSSL, Readline, zlib) that Ruby’s C-extensions need.</li>
  181.  
  182. <li><strong>GPG Key Import</strong><br>RVM’s install script is signed importing its public keys ensures we trust the code we’re running.</li>
  183.  
  184. <li><strong>RVM Setup</strong><br>If RVM isn’t present, we bootstrap it via <code>curl</code>; otherwise, we simply reload the existing install.</li>
  185.  
  186. <li><strong>Ruby Compile &amp; Install</strong><br>All output funnels into our timestamped log for later inspection. On failure, we catch the exit code and bail.</li>
  187.  
  188. <li><strong>Default Ruby &amp; Verification</strong><br>We mark our new Ruby version as the default and print <code>ruby -v</code> so we know it worked.</li></ol><h2 class="wp-block-heading">Extra Practice Functions</h2><p>To stretch your Bash and RVM chops, sprinkle in these helper functions:</p><pre class="wp-block-preformatted"><code># List all known Ruby versions<br>function list_rubies() {<br>  echo "Known Ruby versions:"  <br>  rvm list known<br>}<br><br># Uninstall a specific Ruby version<br>function uninstall_ruby() {<br>  echo "Removing Ruby $1…"  <br>  rvm remove "$1"<br>}<br><br># Create &amp; use a project gemset<br>function setup_gemset() {<br>  echo "Creating gemset '$1'…"  <br>  rvm gemset create "$1"<br>  rvm gemset use "$1"<br>}<br><br># Retry flaky commands up to 3 times<br>function retry() {<br>  local attempt=1 max=3 delay=5<br>  until "$@"; do<br>    if (( attempt == max )); then<br>      echo "Command failed after $attempt tries."  <br>      return 1<br>    fi<br>    (( attempt++ ))<br>    echo "Retry $attempt/$max in $delay sec…"  <br>    sleep $delay<br>  done<br>  return 0<br>}<br></code></pre><p>You can call, for example:</p><pre class="wp-block-preformatted"><code>retry sudo apt-get update</code></pre><p>to guard against transient network failures.</p><h2 class="wp-block-heading">Final Thoughts</h2><p>I used to dread that “status: 100” error. Now, every time it crops up, I let my script handle it logging the details, retrying if necessary, and pointing me straight to the root cause. Automating repetitive setups like Ruby installations frees up my brainpower for the fun parts.</p>]]></content:encoded>
  189. <wfw:commentRss>https://fsiblog.io/how-to-solve-error-while-installing-ruby-using-rvm/feed/</wfw:commentRss>
  190. <slash:comments>0</slash:comments>
  191. <post-id xmlns="com-wordpress:feed-additions:1">2175</post-id> </item>
  192. <item>
  193. <title>How to Resolve _rb_ary_new_from_values Psych Bundle Error in Ruby Applications</title>
  194. <link>https://fsiblog.io/how-to-resolve-_rb_ary_new_from_values-psych-bundle-error-in-ruby-applications/</link>
  195. <comments>https://fsiblog.io/how-to-resolve-_rb_ary_new_from_values-psych-bundle-error-in-ruby-applications/#respond</comments>
  196. <dc:creator><![CDATA[Shaheen Ullah]]></dc:creator>
  197. <pubDate>Sat, 26 Apr 2025 06:39:47 +0000</pubDate>
  198. <category><![CDATA[Ruby]]></category>
  199. <category><![CDATA[Resolve _rb_ary_new_from_values Psych Bundle Error in Ruby]]></category>
  200. <category><![CDATA[Resolve _rb_ary_new_from_values Psych Bundle Error in Ruby Applications]]></category>
  201. <guid isPermaLink="false">https://fsiblog.io/?p=2171</guid>
  202.  
  203. <description><![CDATA[Hi there I’m excited to walk you through a little Ruby adventure I recently had, complete with code, explanations and a sprinkle of hands-on practice. I’ll take you step by step through the problem I ran into, how I reproduced it, what it really means, and finally how I fixed it. Code Error When I [&#8230;]]]></description>
  204. <content:encoded><![CDATA[<p>Hi there I’m excited to walk you through a little Ruby adventure I recently had, complete with code, explanations and a sprinkle of hands-on practice. I’ll take you step by step through the problem I ran into, how I reproduced it, what it really means, and finally how I fixed it.</p><h2 class="wp-block-heading">Code Error</h2><p>When I tried to start my Ruby app, my terminal spat out this scary message:</p><pre class="wp-block-preformatted"><code>: lazy symbol binding failed: Symbol not found: _rb_ary_new_from_values<br>  Referenced from: /Users/rich/.rvm/gems/ruby-2.2.3/gems/psych-2.0.17/lib/psych.bundle<br>  Expected in: flat namespace<br><br>dyld: Symbol not found: _rb_ary_new_from_values<br>  Referenced from: /Users/rich/.rvm/gems/ruby-2.2.3/gems/psych-2.0.17/lib/psych.bundle<br>  Expected in: flat namespace<br><br>Trace/BPT trap: 5<br></code></pre><p>At first glance, it looked like my machine was missing something vital. But really, it was a version mismatch hiding under a confusing error.</p><h2 class="wp-block-heading">Minimal Reproduction</h2><p>To make sure I wasn’t chasing ghosts, I created a tiny Ruby script:</p><pre class="wp-block-preformatted"><code># demo.rb<br>require 'psych'<br><br>yaml_str = &lt;&lt;~YAML<br>  fruits:<br>    - apple<br>    - banana<br>    - cherry<br>YAML<br><br>data = Psych.load(yaml_str)<br>puts data.inspect<br></code></pre><p>Then I ran:</p><pre class="wp-block-preformatted"><code>ruby demo.rb</code></pre><p>and sure enough, the same <code>_rb_ary_new_from_values</code> error showed up. That told me the problem wasn’t in my app it was in how <code>psych</code> was talking to Ruby.</p><h2 class="wp-block-heading">What the Error Means</h2><ul class="wp-block-list"><li><strong><code>dyld: lazy symbol binding failed</code></strong><br>macOS’s dynamic linker (known as <code>dyld</code>) tried to load a C-level function from the <code>psych</code> native extension but couldn’t find it.</li>
  205.  
  206. <li><strong><code>_rb_ary_new_from_values</code></strong><br>This function is part of Ruby’s C-API and was introduced in newer Ruby versions. My <code>psych</code> gem was compiled expecting that function, but at runtime I was using Ruby 2.2.3 which doesn’t provide it.</li>
  207.  
  208. <li><strong>Root Cause</strong><br>A simple version mismatch: the <code>psych</code> gem version I had installed assumed a modern Ruby, but my environment was running an older one.</li></ul><h2 class="wp-block-heading">How I Fixed It</h2><p>I tried two approaches:</p><ul class="wp-block-list"><li><strong>Upgrade Ruby</strong><br>I installed a newer Ruby via RVM:</li></ul><pre class="wp-block-preformatted"><code>install 2.7.6
  209. rvm use 2.7.6 --default
  210. gem uninstall psych
  211. gem install psych</code></pre><p>Now <code>psych</code> would build against a Ruby that actually includes <code>_rb_ary_new_from_values</code>.</p><ul class="wp-block-list"><li><strong>Pin <code>psych</code> to a Compatible Version</strong><br>If you can’t upgrade Ruby, you can choose a <code>psych</code> version that still works on 2.2.3. In my project’s <code>Gemfile</code> I added: </li></ul><pre class="wp-block-preformatted"><code>gem 'psych', '~> 2.0', '&lt; 2.0.17'</code></pre><p>Then ran</p><pre class="wp-block-preformatted">bundle update psych</pre><p>Either way, rebuilding the native extension made the error disappear.</p><h2 class="wp-block-heading">Enhanced Demo with Error Handling &amp; Practice</h2><p>I didn’t stop at just fixing it I also beefed up my demo script to:</p><ul class="wp-block-list"><li>Detect if <code>psych</code> fails to load</li>
  212.  
  213. <li>Fall back to Ruby’s pure-Ruby <code>YAML</code> parser</li>
  214.  
  215. <li>Offer an interactive CLI so I (or you!) can paste any YAML and see how it parses</li></ul><pre class="wp-block-preformatted"><code>#!/usr/bin/env ruby<br># enhanced_demo.rb<br><br>begin<br>  require 'psych'<br>  PARSER = :psych<br>rescue StandardError => e<br>  warn "[Warning] psych load failed: #{e.class} – #{e.message}"<br>  require 'yaml'<br>  PARSER = :syck<br>end<br><br>def load_yaml(str)<br>  PARSER == :psych ? Psych.load(str) : YAML.safe_load(str)<br>end<br><br>def practice_session<br>  puts "Paste YAML (end with blank line):"<br>  lines = []<br>  loop do<br>    line = gets.chomp<br>    break if line.empty?<br>    lines &lt;&lt; line<br>  end<br><br>  input = lines.join("\n")<br>  begin<br>    result = load_yaml(input)<br>    puts "&#x2705; Parsed: #{result.inspect}"<br>  rescue StandardError => e<br>    puts "&#x274c; Parse error: #{e.class}: #{e.message}"<br>  end<br>end<br><br>def main<br>  puts "Using parser: #{PARSER}"<br>  sample = &lt;&lt;~YML<br>    colors:<br>      - red<br>      - green<br>      - blue<br>  YML<br><br>  puts "Sample parse => #{load_yaml(sample).inspect}"<br>  puts "\n--- Your turn! ---"<br>  practice_session<br>end<br><br>main if __FILE__ == $0<br></code></pre><p><strong>How to try it yourself:</strong></p><pre class="wp-block-preformatted"><code>+x enhanced_demo.rb<br>./enhanced_demo.rb<br></code></pre><p>You’ll see which parser is in use, a sample result, and then you can paste your own YAML to see it in action.</p><h2 class="wp-block-heading">Final Thoughts</h2><p>I love how a single error message can lead you down a path of discovery from learning about Ruby’s C-API symbols to mastering fallback strategies and interactive demos. If you ever bump into <code>_rb_ary_new_from_values</code> or any other missing-symbol issue, remember:</p><ul class="wp-block-list"><li>Check for version mismatches first</li>
  216.  
  217. <li>Upgrade Ruby or pin your gems to compatible releases</li>
  218.  
  219. <li>Recompile native extensions when in doubt</li></ul><p>And feel free to use my enhanced demo as a playground for understanding YAML parsing under the hood.</p>]]></content:encoded>
  220. <wfw:commentRss>https://fsiblog.io/how-to-resolve-_rb_ary_new_from_values-psych-bundle-error-in-ruby-applications/feed/</wfw:commentRss>
  221. <slash:comments>0</slash:comments>
  222. <post-id xmlns="com-wordpress:feed-additions:1">2171</post-id> </item>
  223. <item>
  224. <title>How to Resolve Webpack Runtime Issues in Custom Next.js Scripts</title>
  225. <link>https://fsiblog.io/how-to-resolve-webpack-runtime-issues-in-custom-next-js-scripts/</link>
  226. <comments>https://fsiblog.io/how-to-resolve-webpack-runtime-issues-in-custom-next-js-scripts/#respond</comments>
  227. <dc:creator><![CDATA[Bruno Naschpitz]]></dc:creator>
  228. <pubDate>Fri, 25 Apr 2025 05:34:35 +0000</pubDate>
  229. <category><![CDATA[Next.js]]></category>
  230. <category><![CDATA[How to Resolve Webpack Runtime Issues in Custom Next.js]]></category>
  231. <category><![CDATA[Resolve Webpack Runtime Issues in Custom Next.js Scripts]]></category>
  232. <guid isPermaLink="false">https://fsiblog.io/?p=2166</guid>
  233.  
  234. <description><![CDATA[If you&#8217;re working with Next.js and trying to run a custom script for RSS generation like build-rss.js, you might come across an error stating: Error: Cannot find module '../../webpack-runtime.js' This issue can arise due to various reasons, especially after upgrading Next.js or making changes to your build configuration. In this post, I will walk you [&#8230;]]]></description>
  235. <content:encoded><![CDATA[<p>If you&#8217;re working with Next.js and trying to run a custom script for RSS generation like <code>build-rss.js</code>, you might come across an error stating:</p><pre class="wp-block-preformatted"><code>Error: Cannot find module '../../webpack-runtime.js'</code></pre><p>This issue can arise due to various reasons, especially after upgrading Next.js or making changes to your build configuration. In this post, I will walk you through the error&#8217;s explanation, the underlying issue in your configuration, and offer a solution to help you resolve it.</p><h2 class="wp-block-heading">Error Explanation</h2><h3 class="wp-block-heading"><strong>Error Message:</strong></h3><p>The error message <code>Cannot find module '../../webpack-runtime.js'</code> is usually seen when there’s an issue with module resolution, where Node.js cannot locate the <code>webpack-runtime.js</code> file in the expected location.</p><p>This could be related to a few possible causes:</p><ul class="wp-block-list"><li><strong>Incorrect path or module resolution</strong>: The error may appear when Next.js expects certain files to be available, but they are either missing or not correctly linked.</li>
  236.  
  237. <li><strong>Webpack configurations</strong>: If you’ve made custom changes to the webpack configuration (as seen in your <code>next.config.js</code>), it&#8217;s possible that these changes have affected how dependencies are bundled, leading to an issue with module resolution during the build.</li>
  238.  
  239. <li><strong>Next.js version update</strong>: Since you mentioned that the script used to work earlier, but now it doesn&#8217;t, the issue might be related to a version update in Next.js or one of its dependencies that introduced breaking changes in the build process.</li></ul><h2 class="wp-block-heading">Issue in the Configuration</h2><p>In your <code>next.config.js</code>, you&#8217;re trying to dynamically modify the webpack configuration by adding a custom entry point for <code>build-rss.js</code>:</p><pre class="wp-block-preformatted"><code>.exports = {<br>    webpack: (config, options) => {<br>        config.module.rules.push({<br>            test: /\.svg$/,<br>            issuer: { and: [/\.(js|ts|md)x?$/] },<br>            use: [<br>                {<br>                    loader: '@svgr/webpack',<br>                    options: {<br>                        prettier: false,<br>                        svgo: true,<br>                        svgoConfig: { plugins: [{ removeViewBox: false }] },<br>                        titleProp: true,<br>                    },<br>                },<br>            ],<br>        });<br><br>        if (!options.dev &amp;&amp; options.isServer) {<br>            const originalEntry = config.entry;<br>            config.entry = async () => {<br>                const entries = { ...(await originalEntry()) };<br>                entries['./scripts/build-rss'] = './scripts/build-rss.js';<br>                return entries;<br>            };<br>        }<br><br>        if (!options.isServer) {<br>            config.resolve.fallback.fs = false;<br>        }<br><br>        return config;<br>    },<br>}<br></code></pre><p>The part of the configuration that modifies the <code>config.entry</code> is trying to inject the RSS script into the build process. However, this can sometimes lead to problems if Next.js isn’t able to resolve or find <code>webpack-runtime.js</code> properly in the new build context.</p><h2 class="wp-block-heading">Solution and Fix</h2><ul class="wp-block-list"><li><strong>Check File Paths</strong>: Ensure that your <code>build-rss.js</code> script is located correctly and that the path in <code>config.entry</code> correctly points to it. The file should be inside the <code>scripts/</code> folder at the root of your project, as specified in the <code>next.config.js</code>.</li>
  240.  
  241. <li><strong>Modify Webpack Configuration for Serverless</strong>: When using <code>node ./.next/serverless/scripts/build-rss.js</code>, ensure that the build process in a serverless setup can still access the necessary Webpack runtime files. You can try a different approach by modifying the script path resolution based on the build mode (serverless vs. regular server).</li>
  242.  
  243. <li><strong>Test with <code>npm run build</code> First</strong>: Sometimes, running <code>npm run build</code> and ensuring that the build process completes successfully before running custom scripts can help isolate issues related to build-time configuration.</li>
  244.  
  245. <li><strong>Next.js Version Compatibility</strong>: If the issue arose after upgrading Next.js, it might be related to compatibility issues between the custom webpack configuration and newer Next.js versions. Ensure you are using a compatible version of Next.js and check the changelogs for any breaking changes in how webpack is handled.</li>
  246.  
  247. <li><strong>Add Fallback for Webpack Runtime</strong>: You can add a fallback in your <code>next.config.js</code> to ensure that the Webpack runtime is correctly bundled for your script. You can use something like: </li></ul><pre class="wp-block-preformatted"><code>if (!options.isServer) {
  248.    config.resolve.fallback = {
  249.        fs: false,
  250.        path: false,
  251.        webpack: require.resolve('webpack'),
  252.    };
  253. }</code></pre><ul class="wp-block-list"><li><strong>Simplify Webpack Configuration</strong>: Consider simplifying the custom webpack configuration temporarily to identify which part is causing the issue. For example, remove the <code>build-rss.js</code> entry configuration and test if the error still persists.</li></ul><h3 class="wp-block-heading">Improved Script Handling in <code>package.json</code></h3><p>You can simplify your <code>scripts</code> in <code>package.json</code> to ensure the build and export processes work seamlessly, like so:</p><pre class="wp-block-preformatted"><code>"scripts": {<br>    "clean": "rimraf .next",<br>    "dev": "next dev",<br>    "export": "next export",<br>    "start": "next start",<br>    "lint": "next lint",<br>    "build:development": "next build &amp;&amp; npm run export &amp;&amp; npm run rss:development",<br>    "build": "next build &amp;&amp; npm run export &amp;&amp; npm run rss",<br>    "rss:development": "node ./.next/server/scripts/build-rss.js",<br>    "rss": "node ./.next/serverless/scripts/build-rss.js"<br>}<br></code></pre><p>Ensure that you are pointing to the correct location of <code>build-rss.js</code> depending on whether you are using a server-side build or serverless functions.</p><h3 class="wp-block-heading">Further Testing</h3><p>Once you apply these changes, follow these steps to troubleshoot and test:</p><ol class="wp-block-list"><li><strong>Run a Clean Build</strong>: Use <code>npm run clean</code> and then <code>npm run build:development</code> to ensure a fresh build.</li>
  254.  
  255. <li><strong>Test Without Custom Webpack</strong>: Temporarily remove the custom webpack modifications and test if the issue still arises.</li>
  256.  
  257. <li><strong>Check for Updates</strong>: Ensure all dependencies are up to date by running <code>npm outdated</code> and updating packages if necessary.</li></ol><h2 class="wp-block-heading">Conclusion</h2><p>The error you encountered, <code>Cannot find module '../../webpack-runtime.js'</code>, is likely caused by incorrect handling of the Webpack runtime in your custom Next.js configuration. By ensuring the paths are correct, simplifying your webpack config, and checking compatibility with the Next.js version you&#8217;re using, you should be able to resolve this issue.</p>]]></content:encoded>
  258. <wfw:commentRss>https://fsiblog.io/how-to-resolve-webpack-runtime-issues-in-custom-next-js-scripts/feed/</wfw:commentRss>
  259. <slash:comments>0</slash:comments>
  260. <post-id xmlns="com-wordpress:feed-additions:1">2166</post-id> </item>
  261. <item>
  262. <title>How to Fix Undefined Error with GraphQL Request in Next.js</title>
  263. <link>https://fsiblog.io/how-to-fix-undefined-error-with-graphql-request-in-next-js/</link>
  264. <comments>https://fsiblog.io/how-to-fix-undefined-error-with-graphql-request-in-next-js/#respond</comments>
  265. <dc:creator><![CDATA[Bruno Naschpitz]]></dc:creator>
  266. <pubDate>Fri, 25 Apr 2025 05:18:20 +0000</pubDate>
  267. <category><![CDATA[Next.js]]></category>
  268. <category><![CDATA[Fix Undefined Error with GraphQL Request in Next.js]]></category>
  269. <category><![CDATA[Undefined Error with GraphQL Request in Next.js]]></category>
  270. <guid isPermaLink="false">https://fsiblog.io/?p=2163</guid>
  271.  
  272. <description><![CDATA[When you&#8217;re working with Next.js and Contentful, dynamic pages may sometimes return an &#8220;undefined&#8221; error when making GraphQL requests. This issue is common and often occurs due to improper query structure or missing error handling. I&#8217;ll explain the problem, walk through the fix, and show you the corrected code that should solve your issue. Error [&#8230;]]]></description>
  273. <content:encoded><![CDATA[<p>When you&#8217;re working with Next.js and Contentful, dynamic pages may sometimes return an &#8220;undefined&#8221; error when making GraphQL requests. This issue is common and often occurs due to improper query structure or missing error handling. I&#8217;ll explain the problem, walk through the fix, and show you the corrected code that should solve your issue.</p><h2 class="wp-block-heading">Error Code</h2><pre class="wp-block-preformatted"><code>console.error("There was a problem retrieving entries with the query:", query);<br>console.error("Error details:", error);</code></pre><h2 class="wp-block-heading">Explanation of the Error</h2><h3 class="wp-block-heading">GraphQL Query Issue:</h3><p>In your <code>getStaticProps</code>, you&#8217;re constructing a GraphQL query with a dynamic <code>slug</code>, but you aren&#8217;t passing the value correctly into the query. Instead of dynamically passing <code>context.params.slug</code> into the GraphQL query, you&#8217;re likely interpreting it as a string literal. This means the query is looking for an exact match of <code>"context.params.slug"</code> instead of the value you intend.</p><h3 class="wp-block-heading">Query Construction:</h3><p>The GraphQL query you&#8217;re using to fetch posts based on <code>slug</code> is not correctly formatted to handle dynamic values. This issue often causes Contentful to return an empty or undefined response when fetching dynamic pages, even though the same query works for the static news page.</p><h3 class="wp-block-heading">Dynamic Data Handling:</h3><p>The issue might also lie in how the <code>getStaticProps</code> and <code>getStaticPaths</code> functions are handling dynamic data from Contentful. If these functions aren’t receiving the expected data from Contentful, it can cause them to return an undefined result.</p><h2 class="wp-block-heading">Solution and Fix</h2><p>To fix this issue, you need to adjust how the <code>slug</code> parameter is passed into your GraphQL query and ensure that it&#8217;s properly interpolated. Below is the refactored code that resolves the issue by correctly passing the dynamic slug to the query.</p><h3 class="wp-block-heading">Refactored Code</h3><h4 class="wp-block-heading">News Article Page (<code>news/[slug].tsx</code>):</h4><pre class="wp-block-preformatted">tsxCopy<code>import { Box, Text } from "@chakra-ui/react";
  274. import React from "react";
  275. import { fetchContent } from "../../utils/contentful";
  276.  
  277. const NewsArticlePage = ({ post }) =&gt; {
  278.  // Ensure post.slug is defined before attempting to use it
  279.  if (!post) {
  280.    return &lt;Box&gt;No Post Found&lt;/Box&gt;;
  281.  }
  282.  
  283.  return (
  284.    &lt;Box&gt;
  285.      &lt;Text&gt;{post.title}&lt;/Text&gt;
  286.      &lt;Text&gt;{post.slug}&lt;/Text&gt;
  287.    &lt;/Box&gt;
  288.  );
  289. };
  290.  
  291. export default NewsArticlePage;
  292.  
  293. // Fetching data for dynamic pages
  294. export async function getStaticProps({ params }) {
  295.  console.log("Fetching post for slug:", params.slug);
  296.  
  297.  const response = await fetchContent(`
  298.    query getBlogPost($slug: String!) {
  299.      blogPostCollection(where: {slug: $slug}) {
  300.        items {
  301.          title
  302.          slug
  303.        }
  304.      }
  305.    }
  306.  `, { slug: params.slug });
  307.  
  308.  console.log("Response:", response);
  309.  
  310.  const post = response?.blogPostCollection?.items?.[0] || null;
  311.  
  312.  if (!post) {
  313.    return { props: {} }; // Return empty props if no post found
  314.  }
  315.  
  316.  return {
  317.    props: {
  318.      post,
  319.    },
  320.  };
  321. }
  322.  
  323. export async function getStaticPaths() {
  324.  const response = await fetchContent(`
  325.    query {
  326.      blogPostCollection {
  327.        items {
  328.          slug
  329.        }
  330.      }
  331.    }
  332.  `);
  333.  
  334.  const paths = response?.blogPostCollection?.items.map((post) =&gt; ({
  335.    params: { slug: post.slug },
  336.  })) || [];
  337.  
  338.  return {
  339.    paths,
  340.    fallback: false,
  341.  };
  342. }
  343. </code></pre><h4 class="wp-block-heading">Utility Function to Fetch Data (<code>utils/contentful.js</code>):</h4><pre class="wp-block-preformatted"><code>space = process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID;<br>const accessToken = process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN;<br><br>export async function fetchContent(query, variables = {}) {<br>  try {<br>    const res = await fetch(<br>      `https://graphql.contentful.com/content/v1/spaces/${space}`,<br>      {<br>        method: "POST",<br>        headers: {<br>          "Content-Type": "application/json",<br>          "Authorization": `Bearer ${accessToken}`,<br>        },<br>        body: JSON.stringify({ query, variables }),<br>      }<br>    );<br><br>    if (!res.ok) {<br>      throw new Error("Network response was not ok");<br>    }<br><br>    const { data } = await res.json();<br><br>    return data;<br>  } catch (error) {<br>    console.error("Error fetching data from Contentful:", error);<br>    throw error; // Propagate the error to be handled elsewhere<br>  }<br>}<br></code></pre><h2 class="wp-block-heading">Key Fixes:</h2><ol class="wp-block-list"><li><strong>Query Formatting</strong>: In the GraphQL query, the <code>slug</code> value is now passed as a variable (<code>$slug</code>) and included in the request through the <code>variables</code> parameter.</li>
  344.  
  345. <li><strong>Error Handling</strong>: I added better error handling within the <code>fetchContent</code> function using a <code>try-catch</code> block. This allows you to catch network errors or API-related issues and log them for debugging.</li>
  346.  
  347. <li><strong>Fetching Single Post</strong>: The way the post is fetched from the response has been modified. Instead of assuming a fixed structure, we safely access the first item in the response with <code>response?.blogPostCollection?.items?.[0]</code>.</li>
  348.  
  349. <li><strong>Dynamic Paths Handling</strong>: The <code>getStaticPaths</code> function now fetches only the <code>slug</code> field for each post, which is sufficient for generating static paths. This ensures that a dynamic page is generated for each unique <code>slug</code>.</li></ol><h2 class="wp-block-heading">Additional Functionality:</h2><ol class="wp-block-list"><li><strong>Error Handling for Undefined Posts</strong>: I added a safeguard to handle cases where no post is found, displaying a fallback message like &#8220;No Post Found&#8221; on the page. This will help you debug if something goes wrong.</li>
  350.  
  351. <li><strong>Query Optimization</strong>: The <code>getStaticProps</code> function is now optimized to properly accept the <code>slug</code> as a variable, reducing the chance of errors related to incorrect query construction.</li></ol><h2 class="wp-block-heading">Further Improvements:</h2><ol class="wp-block-list"><li><strong>Fallback Handling</strong>: If you want Next.js to regenerate pages on-demand when new posts are added, you can modify the <code>getStaticPaths</code> fallback behavior to <code>true</code>. This way, it won&#8217;t block new slugs from appearing, and the page will be generated on the fly for those slugs that were not pre-generated.</li>
  352.  
  353. <li><strong>Caching</strong>: To minimize the number of requests to Contentful and improve performance, you could implement caching mechanisms such as using a CDN or storing the data locally for a set amount of time.</li></ol><h2 class="wp-block-heading">Conclusion</h2><p>By ensuring the GraphQL query is properly constructed with dynamic variables and improving error handling in the fetch function, this solution should resolve the undefined error you&#8217;re encountering when working with dynamic pages in Next.js and Contentful. Always ensure that the <code>slug</code> or other dynamic parameters are correctly passed into the query, and handle edge cases like missing posts or errors gracefully.</p>]]></content:encoded>
  354. <wfw:commentRss>https://fsiblog.io/how-to-fix-undefined-error-with-graphql-request-in-next-js/feed/</wfw:commentRss>
  355. <slash:comments>0</slash:comments>
  356. <post-id xmlns="com-wordpress:feed-additions:1">2163</post-id> </item>
  357. <item>
  358. <title>How Fix VS Code PHP Intelephense Undefined Symbol Errors in Laravel</title>
  359. <link>https://fsiblog.io/how-fix-vs-code-php-intelephense-undefined-symbol-errors-in-laravel/</link>
  360. <comments>https://fsiblog.io/how-fix-vs-code-php-intelephense-undefined-symbol-errors-in-laravel/#respond</comments>
  361. <dc:creator><![CDATA[MALIK SHAFI]]></dc:creator>
  362. <pubDate>Thu, 24 Apr 2025 05:46:53 +0000</pubDate>
  363. <category><![CDATA[PHP]]></category>
  364. <category><![CDATA[Fix VS Code PHP Intelephense Undefined Symbol Errors in Laravel]]></category>
  365. <category><![CDATA[How Fix VS Code PHP Intelephense Undefined Symbol Errors in Laravel]]></category>
  366. <guid isPermaLink="false">https://fsiblog.io/?p=2159</guid>
  367.  
  368. <description><![CDATA[I’m excited to share how I tackled a pesky “undefined symbol” warning that cropped up in Visual Studio Code after today’s PHP Intelephense update. If you’re working on a Laravel project and suddenly see red squiggles under perfectly good routes even though everything runs fine this post is for you. I’ll walk through exactly what [&#8230;]]]></description>
  369. <content:encoded><![CDATA[<p>I’m excited to share how I tackled a pesky “undefined symbol” warning that cropped up in Visual Studio Code after today’s PHP Intelephense update. If you’re working on a Laravel project and suddenly see red squiggles under perfectly good routes even though everything runs fine this post is for you. I’ll walk through exactly what happened, why Intelephense started complaining, how I fixed it, and even add a bit of practice code so you can confirm everything’s humming along smoothly.</p><h2 class="wp-block-heading">Error Code Snippet</h2><p>Here’s the exact block that triggered the false alarm in my editor:</p><pre class="wp-block-preformatted"><code>&lt;?php<br><br>use Illuminate\Support\Facades\Route;<br><br>Route::group([<br>    'prefix'    =&gt; 'user',<br>    'namespace' =&gt; 'Membership',<br>    'name'      =&gt; 'user.'<br>], function () {<br>    Route::get('profile',           'ProfileController@show')-&gt;name('profile.show');<br>    Route::patch('profile',         'ProfileController@update')-&gt;name('profile.update');<br>    Route::patch('change-password', 'ChangePasswordController@change')-&gt;name('change-password');<br>    Route::get('role',              'ProfileController@getRole')-&gt;name('profile.role');<br>    Route::get('summary',           'SummaryController@show')-&gt;name('summary');<br>    Route::get('reserved',          'AuctionController@reservedAuction')-&gt;name('reserved');<br>});<br></code></pre><p>Everything here is standard Laravel routing. There’s no typo, and the controllers exist in <code>app/Http/Controllers/Membership</code>. Yet Intelephense underlined each controller reference as “undefined symbol.”</p><h2 class="wp-block-heading">The “Undefined Symbol” Error</h2><p>Intelephense flagged lines like this:</p><p>Undefined symbol: Membership\ProfileController</p><p>That’s a <strong>false positive</strong> Laravel resolves these classes at runtime via PSR-4 autoloading, but Intelephense didn’t know where to look in my workspace.</p><h2 class="wp-block-heading">Why Intelephense Complains</h2><ol class="wp-block-list"><li><strong>PSR-4 Autoloading</strong><br>Laravel’s <code>composer.json</code> maps namespaces to folders.</li>
  370.  
  371. <li><strong>Default Indexing</strong><br>Intelephense only scans files directly under your workspace root.</li>
  372.  
  373. <li><strong>Missing Include Paths</strong><br>If you haven’t told Intelephense where your controller folders live, it won’t index them, so references look “undefined.”</li></ol><h2 class="wp-block-heading">How I Fixed It</h2><ul class="wp-block-list"><li>Open <strong>Settings</strong> in VS Code (Ctrl + <code>,</code>).</li>
  374.  
  375. <li>Search for <code>intelephense.environment.includePaths</code>.</li>
  376.  
  377. <li>Edit your <code>settings.json</code> and add the directories where your PHP classes live:</li></ul><pre class="wp-block-preformatted"><code>// settings.json
  378. {
  379.  "intelephense.environment.includePaths": [
  380.    "app/Http/Controllers",
  381.    "app/Models"
  382.  ]
  383. }</code></pre><ul class="wp-block-list"><li>Reload VS Code so Intelephense re-indexes everything.</li>
  384.  
  385. <li>Goodbye, red squiggles!</li></ul><h2 class="wp-block-heading">Adding Practice Functionality</h2><p>Once my IDE stopped complaining, I wanted to be sure my routes still worked—and give myself some playground code. I extended the <code>user</code> group with three quick test endpoints:</p><pre class="wp-block-preformatted"><code>&lt;?php<br><br>use Illuminate\Support\Facades\Route;<br>use Illuminate\Http\Request;<br><br>Route::group([<br>    'prefix'    =&gt; 'user',<br>    'namespace' =&gt; 'Membership',<br>    'name'      =&gt; 'user.'<br>], function () {<br>    // …original routes above…<br><br>    // 1) Return the authenticated user as JSON<br>    Route::get('me', function (Request $request) {<br>        return response()-&gt;json($request-&gt;user());<br>    })-&gt;name('profile.me')-&gt;middleware('auth');<br><br>    // 2) Search reserved auctions by date (YYYY-MM-DD)<br>    Route::get('reserved/search', 'AuctionController@searchByDate')<br>         -&gt;name('reserved.search')<br>         -&gt;where('date', '\d{4}-\d{2}-\d{2}');<br><br>    // 3) Bulk update profile settings<br>    Route::patch('settings', 'ProfileController@bulkUpdate')<br>         -&gt;name('settings.bulk-update');<br>});<br></code></pre><h2 class="wp-block-heading">Practice Tasks</h2><ul class="wp-block-list"><li><strong>Visit</strong> <code>/user/me</code> after logging in. You should see your user record in JSON.</li>
  386.  
  387. <li><strong>Open</strong> <code>/user/reserved/search?date=2025-04-24</code> to test date filtering.</li>
  388.  
  389. <li><strong>Send</strong> a <code>PATCH</code> to <code>/user/settings</code> with a small JSON payload to verify your bulk update logic.</li></ul><h2 class="wp-block-heading">Final Thoughts</h2><p>False positives from IDE tools can be an annoying distraction, but they’re usually fixable with a little configuration. Once I pointed Intelephense at my Laravel folders, those phantom “undefined symbol” errors disappeared. Adding some extra test routes not only confirmed my setup but also gave me a reusable snippet for future projects.</p>]]></content:encoded>
  390. <wfw:commentRss>https://fsiblog.io/how-fix-vs-code-php-intelephense-undefined-symbol-errors-in-laravel/feed/</wfw:commentRss>
  391. <slash:comments>0</slash:comments>
  392. <post-id xmlns="com-wordpress:feed-additions:1">2159</post-id> </item>
  393. <item>
  394. <title>How to Send Specific Invoice Values with Stripe PHP Invoice</title>
  395. <link>https://fsiblog.io/how-to-send-specific-invoice-values-with-stripe-php-invoice/</link>
  396. <comments>https://fsiblog.io/how-to-send-specific-invoice-values-with-stripe-php-invoice/#respond</comments>
  397. <dc:creator><![CDATA[MALIK SHAFI]]></dc:creator>
  398. <pubDate>Thu, 24 Apr 2025 05:27:34 +0000</pubDate>
  399. <category><![CDATA[PHP]]></category>
  400. <category><![CDATA[How to Send Specific Invoice Values with Stripe PHP Invoice]]></category>
  401. <category><![CDATA[Send Specific Invoice Values with Stripe PHP Invoice]]></category>
  402. <guid isPermaLink="false">https://fsiblog.io/?p=2156</guid>
  403.  
  404. <description><![CDATA[I’m a developer who’s been in your shoes trying to get Stripe to bill customers exactly the right amount, only to discover those invoices keep coming through for £0. In this walkthrough, I’ll share my own Stripe PHP invoice setup for music lesson billing, explain where things went wrong, and offer ideas to level up [&#8230;]]]></description>
  405. <content:encoded><![CDATA[<p>I’m a developer who’s been in your shoes trying to get Stripe to bill customers exactly the right amount, only to discover those invoices keep coming through for £0. In this walkthrough, I’ll share my own Stripe PHP invoice setup for music lesson billing, explain where things went wrong, and offer ideas to level up your invoicing flow with discounts and reminders. By the end, you’ll have a solid, working function and inspiration for extra practice features.</p><h2 class="wp-block-heading">Error Code</h2><p>Here’s the cleaned-up <code>createStripeLessonInvoice</code> function I ended up using. I’ve added clear logging, a single finalize step, and return the hosted invoice URL once everything’s locked in.</p><pre class="wp-block-preformatted"><code>&lt;?php<br>require 'vendor/autoload.php'; // Load the Stripe PHP library<br><br>function createStripeLessonInvoice(<br>    string $parentName,<br>    string $email,<br>    string $childName,<br>    string $instrument,<br>    string $grouping,<br>    float  $costPerLesson,<br>    int    $lessonCount<br>): ?string {<br>    \Stripe\Stripe::setApiKey('sk_test_[MYKEY]');<br><br>    try {<br>        // 1) Get or create the Stripe customer<br>        $customer = getOrCreateStripeCustomer($email, $parentName, null, $childName);<br><br>        // 2) Calculate the total and convert to pence<br>        $totalCost   = $costPerLesson * $lessonCount;<br>        $amountPence = (int) round($totalCost * 100);<br><br>        error_log("DEBUG: Total cost is £{$totalCost}");<br>        error_log("DEBUG: Amount in pence: {$amountPence}");<br><br>        // 3) Create a single invoice item<br>        $invoiceItem = \Stripe\InvoiceItem::create([<br>            'customer'    => $customer->id,<br>            'amount'      => $amountPence,<br>            'currency'    => 'gbp',<br>            'description' => "{$lessonCount} × £{$costPerLesson} lessons",<br>            'metadata'    => [<br>                'student_name' => $childName,<br>                'instrument'   => $instrument,<br>                'grouping'     => $grouping,<br>                'lesson_count' => $lessonCount,<br>                'unit_cost'    => $costPerLesson,<br>                'total_cost'   => $totalCost,<br>            ],<br>        ]);<br><br>        // 4) Create the invoice, schedule to send in 7 days<br>        $invoice = \Stripe\Invoice::create([<br>            'customer'          => $customer->id,<br>            'collection_method' => 'send_invoice',<br>            'days_until_due'    => 7,<br>            'auto_advance'      => false, // we’ll call finalize manually<br>        ]);<br><br>        // 5) Finalize the invoice so it moves from draft to open<br>        $finalizedInvoice = $invoice->finalizeInvoice();<br>        error_log("DEBUG: Invoice finalized: " . print_r($finalizedInvoice, true));<br><br>        // 6) (Optional) Send immediately:<br>        // \Stripe\Invoice::sendInvoice($finalizedInvoice->id);<br><br>        // 7) Return the URL to share with your customer<br>        return $finalizedInvoice->hosted_invoice_url;<br><br>    } catch (\Stripe\Exception\ApiErrorException $e) {<br>        error_log('Stripe API error: ' . $e->getMessage());<br>        return null;<br>    }<br>}<br></code></pre><h2 class="wp-block-heading">Error Definition</h2><p>In my first iteration, I had two calls to <code>finalizeInvoice()</code> and two early <code>return</code> statements. That meant:</p><ul class="wp-block-list"><li>The very first <code>return</code> ran before I logged anything or finalized properly.</li>
  406.  
  407. <li>No invoice items ever attached, so Stripe generated a blank (zero-value) invoice.</li>
  408.  
  409. <li>My logs never showed the real error or amount in pence, leaving me clueless.</li></ul><p>By consolidating to a single finalize and moving the <code>return</code> to the end, I can see exactly what’s happening in my logs—and Stripe now charges the correct amount.</p><h2 class="wp-block-heading">Explanation of the Stripe Flow</h2><ol class="wp-block-list"><li><strong><code>InvoiceItem::create</code></strong><br>I add one or more line items (here, my lessons) to the customer’s upcoming invoice. Remember: Stripe expects amounts in the smallest currency unit (pence for GBP).</li>
  410.  
  411. <li><strong><code>Invoice::create</code></strong><br>This builds a draft invoice for the customer, automatically including any pending invoice items.</li>
  412.  
  413. <li><strong><code>Invoice::finalizeInvoice</code></strong><br>Finalizes the draft—locking in totals and making line items appear on the hosted invoice page.</li>
  414.  
  415. <li><strong>(Optional) <code>Invoice::sendInvoice</code></strong><br>You can call this immediately if you don’t want to wait for Stripe’s scheduled send. Otherwise, Stripe will auto-send on the date you set.</li></ol><h2 class="wp-block-heading">Additional Practice Functionality</h2><p>To take your invoicing further, try these extras in your own project:</p><h3 class="wp-block-heading">Multiple Line-Items &amp; Discounts</h3><pre class="wp-block-preformatted"><code>function addLessonPackage($customerId, $description, $unitCost, $quantity) {<br>    \Stripe\InvoiceItem::create([<br>        'customer'    => $customerId,<br>        'amount'      => (int) round($unitCost * $quantity * 100),<br>        'currency'    => 'gbp',<br>        'description' => "{$quantity}× {$description}",<br>    ]);<br>}<br><br>function addDiscount($customerId, float $discountAmount) {<br>    \Stripe\InvoiceItem::create([<br>        'customer'    => $customerId,<br>        'amount'      => -(int) round($discountAmount * 100),<br>        'currency'    => 'gbp',<br>        'description' => "Discount: £" . number_format($discountAmount, 2),<br>    ]);<br>}<br><br>// Usage example:<br>addLessonPackage($customer->id, 'Group Piano Lessons', 25.00, 4);<br>addDiscount($customer->id, 10.00);<br></code></pre><h3 class="wp-block-heading">Automated Reminder Emails</h3><p>Hook into Stripe’s webhooks listen for <code>invoice.finalized</code> and then schedule your own email reminder a day before the due date. Rough sketch:</p><pre class="wp-block-preformatted"><code>// webhook-handler.php<br>$payload = json_decode(file_get_contents('php://input'), true);<br>if ($payload['type'] === 'invoice.finalized') {<br>    $invoice = $payload['data']['object'];<br>    scheduleReminderEmail(<br>        $invoice['customer_email'],<br>        (new DateTime())->setTimestamp($invoice['due_date'])->modify('-1 day')<br>    );<br>}<br></code></pre><h2 class="wp-block-heading">Final Thoughts</h2><p>Billing students for music lessons shouldn’t feel like wrestling with Stripe’s API. By logging pence values, finalizing once, and returning the hosted URL last, you’ll see correct invoices every time. Then, when you’re comfortable, add multiple items, apply discounts, or build reminder hooks to automate follow-ups.</p>]]></content:encoded>
  416. <wfw:commentRss>https://fsiblog.io/how-to-send-specific-invoice-values-with-stripe-php-invoice/feed/</wfw:commentRss>
  417. <slash:comments>0</slash:comments>
  418. <post-id xmlns="com-wordpress:feed-additions:1">2156</post-id> </item>
  419. </channel>
  420. </rss>
  421.  

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid RSS" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=https%3A//fsiblog.io/feed/

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda