<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>BlogByNuX</title><link href="/" rel="alternate"/><link href="/feeds/all.atom.xml" rel="self"/><id>/</id><updated>2026-10-01T00:00:00-07:00</updated><subtitle>Tech, Tales, &amp; Beyond – A blend of technology, life, and everything else.</subtitle><entry><title>Foundation, Foundation, Foundation</title><link href="/foundation-foundation-foundation.html" rel="alternate"/><published>2026-10-01T00:00:00-07:00</published><updated>2026-10-01T00:00:00-07:00</updated><author><name>NuX</name></author><id>tag:None,2026-10-01:/foundation-foundation-foundation.html</id><summary type="html">&lt;p&gt;Network automation is not just a technology problem. Without a shared foundation, consistent processes, and people rowing in the same direction, even the best tools can only get you so far.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Imagine spending the better part of an afternoon painting a fence.&lt;/p&gt;
&lt;p&gt;Stroke.&lt;/p&gt;
&lt;p&gt;Dip.&lt;/p&gt;
&lt;p&gt;Stroke.&lt;/p&gt;
&lt;p&gt;Dip.&lt;/p&gt;
&lt;p&gt;A few hours go by and you're finally starting to see progress.&lt;/p&gt;
&lt;p&gt;Then you look back and realize the neighbor kid has been throwing clods of dirt at the part you already finished.&lt;/p&gt;
&lt;p&gt;That is sometimes what trying to introduce programmability and automation into networking feels like.&lt;/p&gt;
&lt;p&gt;You can have the scripts.&lt;/p&gt;
&lt;p&gt;You can have the APIs.&lt;/p&gt;
&lt;p&gt;You can have the Python libraries, the templates, the source of truth, the automation servers, and the best intentions in the world.&lt;/p&gt;
&lt;p&gt;But if the foundation is not there, one person can undo a surprising amount of work.&lt;/p&gt;
&lt;p&gt;Sometimes intentionally.&lt;/p&gt;
&lt;p&gt;Usually unintentionally.&lt;/p&gt;
&lt;p&gt;Either way, the result is the same.&lt;/p&gt;
&lt;p&gt;You spend your time repainting the fence.&lt;/p&gt;
&lt;h2&gt;Everyone Has to Row in the Same Direction&lt;/h2&gt;
&lt;p&gt;&lt;img alt="A chaotic boat crew rowing in different directions while one person chews on an oar" src="/images/foundation-rowers-chaos.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sometimes the crew isn't just rowing in different directions. Sometimes one guy is chewing on the oar.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When programming concepts are applied to networking, a foundation has to exist first.&lt;/p&gt;
&lt;p&gt;Standards.&lt;/p&gt;
&lt;p&gt;Processes.&lt;/p&gt;
&lt;p&gt;Trust.&lt;/p&gt;
&lt;p&gt;Access.&lt;/p&gt;
&lt;p&gt;Consistency.&lt;/p&gt;
&lt;p&gt;People who understand what the automation is trying to accomplish.&lt;/p&gt;
&lt;p&gt;And, perhaps most importantly, support from the people responsible for the environment.&lt;/p&gt;
&lt;p&gt;I can already hear somebody saying:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One person can't disrupt an automation effort that badly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sure they can.&lt;/p&gt;
&lt;p&gt;Imagine building an automation platform that depends on reaching a set of network devices from a known group of systems.&lt;/p&gt;
&lt;p&gt;Then somebody modifies an access control list.&lt;/p&gt;
&lt;p&gt;Maybe they do not know those systems are automation hosts.&lt;/p&gt;
&lt;p&gt;Maybe they do know and have a different idea of how things should work.&lt;/p&gt;
&lt;p&gt;Either way, your automation stops.&lt;/p&gt;
&lt;p&gt;Nothing about Python changed.&lt;/p&gt;
&lt;p&gt;Nothing about your code changed.&lt;/p&gt;
&lt;p&gt;Nothing about the API changed.&lt;/p&gt;
&lt;p&gt;The environment changed underneath you.&lt;/p&gt;
&lt;p&gt;And suddenly the problem is no longer technical.&lt;/p&gt;
&lt;h2&gt;Technology Can't Solve Every Problem&lt;/h2&gt;
&lt;p&gt;That has probably been one of the more frustrating lessons of my career.&lt;/p&gt;
&lt;p&gt;Technology can solve a lot of things.&lt;/p&gt;
&lt;p&gt;It cannot make people cooperate.&lt;/p&gt;
&lt;p&gt;It cannot make an organization agree on standards.&lt;/p&gt;
&lt;p&gt;It cannot make a manager support a direction they do not believe in.&lt;/p&gt;
&lt;p&gt;It cannot make a process consistent when everybody is allowed to invent their own version of it.&lt;/p&gt;
&lt;p&gt;It cannot turn a dysfunctional environment into a functional one merely because somebody installed Ansible.&lt;/p&gt;
&lt;p&gt;Sometimes the biggest obstacle to automation has absolutely nothing to do with automation.&lt;/p&gt;
&lt;h2&gt;When Networking and Programming Started Dating&lt;/h2&gt;
&lt;p&gt;There was a period when networking and programming were just beginning to seriously meet each other.&lt;/p&gt;
&lt;p&gt;Today, Python in networking barely raises an eyebrow.&lt;/p&gt;
&lt;p&gt;Back then, it was different.&lt;/p&gt;
&lt;p&gt;Some of the libraries and tools I wanted to use ran cleanly on Linux and were, at best, unpredictable on Windows.&lt;/p&gt;
&lt;p&gt;You could sometimes make them work.&lt;/p&gt;
&lt;p&gt;Sometimes.&lt;/p&gt;
&lt;p&gt;Other times you spent hours fighting dependencies, compilers, strange Python packaging behavior, or libraries that clearly assumed they were running on a Unix-like system.&lt;/p&gt;
&lt;p&gt;Linux was simply the better tool for the job.&lt;/p&gt;
&lt;p&gt;The problem was that sometimes management would say:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No Linux.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That could be frustrating.&lt;/p&gt;
&lt;p&gt;You could lay out the possibilities.&lt;/p&gt;
&lt;p&gt;You could explain how automation might reduce repetitive work.&lt;/p&gt;
&lt;p&gt;You could show how consistency could improve.&lt;/p&gt;
&lt;p&gt;You could talk about configuration generation, validation, reporting, auditing, backups, testing, and all of the other things that become possible once networking starts borrowing ideas from software development.&lt;/p&gt;
&lt;p&gt;You could show the horizon.&lt;/p&gt;
&lt;p&gt;But if the answer was no, the answer was no.&lt;/p&gt;
&lt;p&gt;Technology does not override organizational authority.&lt;/p&gt;
&lt;h2&gt;One Person Can Only Push So Far&lt;/h2&gt;
&lt;p&gt;That is probably the heart of this post.&lt;/p&gt;
&lt;p&gt;One person can build a lot.&lt;/p&gt;
&lt;p&gt;One person can learn a lot.&lt;/p&gt;
&lt;p&gt;One person can prototype.&lt;/p&gt;
&lt;p&gt;One person can demonstrate what is possible.&lt;/p&gt;
&lt;p&gt;One person can even build something from the ground up.&lt;/p&gt;
&lt;p&gt;But one person cannot create organizational alignment by themselves.&lt;/p&gt;
&lt;p&gt;That can be incredibly frustrating.&lt;/p&gt;
&lt;p&gt;You may look at a decision and think it makes absolutely no sense.&lt;/p&gt;
&lt;p&gt;You may see people doing things manually that could have been automated years ago.&lt;/p&gt;
&lt;p&gt;You may see inconsistent configurations, undocumented changes, one-off exceptions, and processes that exist mostly because that is how somebody has always done them.&lt;/p&gt;
&lt;p&gt;Eventually I learned that there is a difference between recognizing dysfunction and believing you are personally responsible for fixing all of it.&lt;/p&gt;
&lt;p&gt;If an opportunity appears to improve something, take it.&lt;/p&gt;
&lt;p&gt;If people want help fixing a broken process, help fix it.&lt;/p&gt;
&lt;p&gt;But if the people, processes, or organization do not want to change, there is only so much force you can apply before you are just exhausting yourself.&lt;/p&gt;
&lt;h2&gt;Sometimes People Have Reasons You Cannot See&lt;/h2&gt;
&lt;p&gt;Years ago I worked for a manager who was actually a pretty sharp guy.&lt;/p&gt;
&lt;p&gt;He understood technology.&lt;/p&gt;
&lt;p&gt;He understood people.&lt;/p&gt;
&lt;p&gt;He understood how to manage.&lt;/p&gt;
&lt;p&gt;But when it came to applying programming techniques to networking, we rarely seemed to see things the same way.&lt;/p&gt;
&lt;p&gt;At the time, I thought one of two things was happening.&lt;/p&gt;
&lt;p&gt;Either he simply did not like me, or he really did not like the direction I was trying to take networking.&lt;/p&gt;
&lt;p&gt;I eventually leaned toward the second explanation.&lt;/p&gt;
&lt;p&gt;Later, I learned that earlier in his career he had worked for a company that was doing some very advanced work for the time around combining programming and networking.&lt;/p&gt;
&lt;p&gt;From what I understood, that experience had not gone particularly well.&lt;/p&gt;
&lt;p&gt;I can only speculate, but I have wondered whether that experience shaped how he viewed the same ideas later.&lt;/p&gt;
&lt;p&gt;And honestly, that would make sense.&lt;/p&gt;
&lt;p&gt;People do not walk into a meeting as blank slates.&lt;/p&gt;
&lt;p&gt;Past failures matter.&lt;/p&gt;
&lt;p&gt;Past outages matter.&lt;/p&gt;
&lt;p&gt;Bad projects matter.&lt;/p&gt;
&lt;p&gt;Being burned by a technology once can make somebody extremely cautious about touching it again.&lt;/p&gt;
&lt;p&gt;At the time, though, I did not understand that.&lt;/p&gt;
&lt;p&gt;All I could see was resistance.&lt;/p&gt;
&lt;h2&gt;Then Something Changed&lt;/h2&gt;
&lt;p&gt;Fast forward several years.&lt;/p&gt;
&lt;p&gt;Maybe close to a decade.&lt;/p&gt;
&lt;p&gt;People move on.&lt;/p&gt;
&lt;p&gt;He did too.&lt;/p&gt;
&lt;p&gt;He moved upward, eventually became a CIO, and later went on to bigger things.&lt;/p&gt;
&lt;p&gt;Eventually he landed at a very large global organization.&lt;/p&gt;
&lt;p&gt;And that organization was heavily invested in things that, years earlier, I had been trying to talk about:&lt;/p&gt;
&lt;p&gt;Linux.&lt;/p&gt;
&lt;p&gt;Automation.&lt;/p&gt;
&lt;p&gt;Agile methods.&lt;/p&gt;
&lt;p&gt;Programming applied to infrastructure.&lt;/p&gt;
&lt;p&gt;Infrastructure being treated more like software.&lt;/p&gt;
&lt;p&gt;After he had been there for a few years, our paths crossed again.&lt;/p&gt;
&lt;p&gt;And something was different.&lt;/p&gt;
&lt;p&gt;The resistance I remembered was gone.&lt;/p&gt;
&lt;p&gt;The ideas that had once been difficult to even discuss were now completely normal.&lt;/p&gt;
&lt;p&gt;Maybe it was exposure.&lt;/p&gt;
&lt;p&gt;Maybe the technology matured.&lt;/p&gt;
&lt;p&gt;Maybe the tools got better.&lt;/p&gt;
&lt;p&gt;Maybe the surrounding culture changed.&lt;/p&gt;
&lt;p&gt;Maybe his earlier concerns were absolutely valid for the environment we were in at the time.&lt;/p&gt;
&lt;p&gt;Probably some combination of all of the above.&lt;/p&gt;
&lt;p&gt;Whatever the reason, it reminded me of something important:&lt;/p&gt;
&lt;p&gt;People change.&lt;/p&gt;
&lt;p&gt;Technology changes.&lt;/p&gt;
&lt;p&gt;Organizations change.&lt;/p&gt;
&lt;p&gt;And sometimes an idea that looks ridiculous in one environment becomes obvious in another.&lt;/p&gt;
&lt;h2&gt;Don't Stop Learning&lt;/h2&gt;
&lt;p&gt;That experience is one of the reasons I believe so strongly in continuing to learn even when your current environment does not give you much opportunity to use what you are learning.&lt;/p&gt;
&lt;p&gt;If you have to build a little lab at home, build the lab.&lt;/p&gt;
&lt;p&gt;If that turns into a mini data center in the garage, well...&lt;/p&gt;
&lt;p&gt;Welcome to the club.&lt;/p&gt;
&lt;p&gt;Learn Linux.&lt;/p&gt;
&lt;p&gt;Learn Python.&lt;/p&gt;
&lt;p&gt;Learn APIs.&lt;/p&gt;
&lt;p&gt;Learn automation.&lt;/p&gt;
&lt;p&gt;Learn how the network actually behaves underneath all of those tools.&lt;/p&gt;
&lt;p&gt;Learn because you are curious.&lt;/p&gt;
&lt;p&gt;Learn because someday the environment around you may finally catch up.&lt;/p&gt;
&lt;p&gt;You never know when the opportunity is going to appear.&lt;/p&gt;
&lt;h2&gt;Foundation, Foundation, Foundation&lt;/h2&gt;
&lt;p&gt;The tools matter.&lt;/p&gt;
&lt;p&gt;The code matters.&lt;/p&gt;
&lt;p&gt;The architecture matters.&lt;/p&gt;
&lt;p&gt;But the foundation matters more.&lt;/p&gt;
&lt;p&gt;It is very hard to get anywhere when you have a boat full of rowers all rowing in different directions.&lt;/p&gt;
&lt;p&gt;I am pretty sure I have even seen one guy start chewing on his oar.&lt;/p&gt;
&lt;p&gt;Automation works best when everybody agrees on some basic truths.&lt;/p&gt;
&lt;p&gt;Where configuration should come from.&lt;/p&gt;
&lt;p&gt;Who is allowed to change it.&lt;/p&gt;
&lt;p&gt;How changes are documented.&lt;/p&gt;
&lt;p&gt;What the source of truth is.&lt;/p&gt;
&lt;p&gt;What standards are expected.&lt;/p&gt;
&lt;p&gt;What systems automation depends on.&lt;/p&gt;
&lt;p&gt;What happens when reality no longer matches the template.&lt;/p&gt;
&lt;p&gt;Without that foundation, automation becomes fragile.&lt;/p&gt;
&lt;p&gt;And that leads to another lesson.&lt;/p&gt;
&lt;h2&gt;Defensive Programming Is Not Paranoia&lt;/h2&gt;
&lt;p&gt;Over the years, I have become much more defensive in how I write network automation.&lt;/p&gt;
&lt;p&gt;Not defensive in the violent sense.&lt;/p&gt;
&lt;p&gt;Defensive in the programming sense.&lt;/p&gt;
&lt;p&gt;Check everything.&lt;/p&gt;
&lt;p&gt;Validate everything.&lt;/p&gt;
&lt;p&gt;Sanitize input.&lt;/p&gt;
&lt;p&gt;Normalize data.&lt;/p&gt;
&lt;p&gt;Verify assumptions.&lt;/p&gt;
&lt;p&gt;Expect drift.&lt;/p&gt;
&lt;p&gt;Expect somebody to change something.&lt;/p&gt;
&lt;p&gt;Expect the network you saw yesterday to be slightly different today.&lt;/p&gt;
&lt;p&gt;If an ACL is supposed to be deployed everywhere, do not assume it is.&lt;/p&gt;
&lt;p&gt;Check.&lt;/p&gt;
&lt;p&gt;If an interface is supposed to have a particular description, do not assume it does.&lt;/p&gt;
&lt;p&gt;Check.&lt;/p&gt;
&lt;p&gt;If a configuration template says one thing and the device says another, treat that difference as information.&lt;/p&gt;
&lt;p&gt;The network is not a static database.&lt;/p&gt;
&lt;p&gt;It is a living environment touched by people, processes, maintenance windows, vendors, outages, troubleshooting sessions, emergency fixes, forgotten exceptions, and the occasional mystery command nobody remembers entering.&lt;/p&gt;
&lt;p&gt;The safest assumption is that assumptions expire.&lt;/p&gt;
&lt;p&gt;That does not mean automation is pointless.&lt;/p&gt;
&lt;p&gt;It means good automation has to account for the fact that reality moves.&lt;/p&gt;
&lt;h2&gt;You Can't Script Culture&lt;/h2&gt;
&lt;p&gt;That may be the biggest lesson of all.&lt;/p&gt;
&lt;p&gt;You can script configuration.&lt;/p&gt;
&lt;p&gt;You can script validation.&lt;/p&gt;
&lt;p&gt;You can script backups.&lt;/p&gt;
&lt;p&gt;You can script audits.&lt;/p&gt;
&lt;p&gt;You can script reports.&lt;/p&gt;
&lt;p&gt;You can script remediation.&lt;/p&gt;
&lt;p&gt;You cannot script culture.&lt;/p&gt;
&lt;p&gt;You cannot automate people into agreeing with each other.&lt;/p&gt;
&lt;p&gt;You cannot &lt;code&gt;pip install&lt;/code&gt; leadership.&lt;/p&gt;
&lt;p&gt;You cannot fix a broken process with a YAML file if nobody agrees that the process is broken.&lt;/p&gt;
&lt;p&gt;The technology still matters.&lt;/p&gt;
&lt;p&gt;Keep learning it.&lt;/p&gt;
&lt;p&gt;Keep building.&lt;/p&gt;
&lt;p&gt;Keep experimenting.&lt;/p&gt;
&lt;p&gt;Keep showing what is possible.&lt;/p&gt;
&lt;p&gt;Just remember that the most sophisticated automation platform in the world still needs something solid underneath it.&lt;/p&gt;
&lt;p&gt;A foundation.&lt;/p&gt;
&lt;p&gt;A shared direction.&lt;/p&gt;
&lt;p&gt;And preferably a crew that has agreed not to eat the oars.&lt;/p&gt;</content><category term="Ramblings"/><category term="Networking"/><category term="Automation"/><category term="Python"/><category term="Linux"/><category term="Leadership"/><category term="Culture"/><category term="Programmability"/><category term="Defensive Programming"/></entry><entry><title>I Put an AI on My Phone Line. Then Another AI Called It.</title><link href="/ai-ivr-phone-line-ai-called-it.html" rel="alternate"/><published>2026-09-30T00:00:00-07:00</published><updated>2026-09-30T00:00:00-07:00</updated><author><name>NuX</name></author><id>tag:None,2026-09-30:/ai-ivr-phone-line-ai-called-it.html</id><summary type="html">&lt;p&gt;I built a local AI-powered IVR using Xfinity, a Cisco ISR4351, Asterisk, Faster-Whisper, Qwen, Ollama, and Coqui XTTS-v2. Then an automated mortgage caller rang it and things got weird.&lt;/p&gt;</summary><content type="html">&lt;h1&gt;I Put an AI on My Phone Line. Then Another AI Called It.&lt;/h1&gt;
&lt;p&gt;This project started because I wanted to play with voice again.&lt;/p&gt;
&lt;p&gt;I have not done much with voice systems in years, and I thought it would be fun to combine some old-school telephony with newer local AI tools. What started as a simple experiment turned into a complete AI-powered IVR that can answer a real telephone call, listen to the caller, transcribe what they say, decide how to respond, generate speech, and send that audio back through the phone system.&lt;/p&gt;
&lt;p&gt;Then something happened that I absolutely did not plan for.&lt;/p&gt;
&lt;p&gt;Another AI called it.&lt;/p&gt;
&lt;p&gt;And, because apparently I cannot leave well enough alone, my AI happened to sound like Duke Nukem.&lt;/p&gt;
&lt;p&gt;Yes. That Duke Nukem.&lt;/p&gt;
&lt;p&gt;The bubble-gum-chewing, alien-kicking video game hero of the 1990s.&lt;/p&gt;
&lt;p&gt;Before I get to that part, though, it probably helps to explain what I actually built.&lt;/p&gt;
&lt;p&gt;&lt;img alt="IVR Voice AI Call Flow" src="/images/ivr-voice-ai-call-flow.png"&gt;&lt;/p&gt;
&lt;h2&gt;The Call Flow&lt;/h2&gt;
&lt;p&gt;The actual path of a call looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Caller
  |
  v
Xfinity Cloud / PSTN
  |
  v
Cisco ISR4351 Router
  |
  | FXO
  v
SIP Trunk
  |
  v
Asterisk 20.6.0
  |
  v
IVR Orchestrator
  |
  v
Faster-Whisper
  |
  v
Qwen 3.5 9B via Ollama
  |
  v
Coqui XTTS-v2
  |
  v
IVR Orchestrator
  |
  v
Asterisk
  |
  v
Caller
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is something I really like about this architecture.&lt;/p&gt;
&lt;p&gt;At one end, I have the public telephone network and an analog FXO interface. That is technology with roots going back decades.&lt;/p&gt;
&lt;p&gt;At the other end, I have local speech recognition, a large language model, and neural text-to-speech.&lt;/p&gt;
&lt;p&gt;A telephone call comes in through Xfinity, crosses the PSTN, hits a Cisco router over FXO, gets converted into SIP, lands in Asterisk, gets handed to an application, becomes text, gets processed by an LLM, becomes speech again, and then travels all the way back out to the caller.&lt;/p&gt;
&lt;p&gt;That is a ridiculous amount of technology involved just to say, "Hello."&lt;/p&gt;
&lt;p&gt;And I love it.&lt;/p&gt;
&lt;h2&gt;Not Everything in the System Is AI&lt;/h2&gt;
&lt;p&gt;One thing I wanted to keep very clear while building this is that the entire system is not "AI."&lt;/p&gt;
&lt;p&gt;There are really three AI workloads in the call path:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Faster-Whisper&lt;/strong&gt; handles speech-to-text.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Qwen 3.5 9B&lt;/strong&gt; handles the conversational response.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coqui XTTS-v2&lt;/strong&gt; turns the generated response back into speech.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Everything else is infrastructure or application logic.&lt;/p&gt;
&lt;p&gt;Asterisk is not AI.&lt;/p&gt;
&lt;p&gt;The Cisco router is not AI.&lt;/p&gt;
&lt;p&gt;The PSTN is definitely not AI.&lt;/p&gt;
&lt;p&gt;Ollama is not the language model itself. It is the runtime serving the model.&lt;/p&gt;
&lt;p&gt;And the IVR orchestrator is intentionally &lt;strong&gt;not&lt;/strong&gt; AI either.&lt;/p&gt;
&lt;p&gt;That part matters.&lt;/p&gt;
&lt;h2&gt;The Orchestrator Is the Traffic Cop&lt;/h2&gt;
&lt;p&gt;The IVR orchestrator is the piece that ties the whole thing together.&lt;/p&gt;
&lt;p&gt;It coordinates the live call between Asterisk, speech recognition, the language model, and text-to-speech.&lt;/p&gt;
&lt;p&gt;Its job is to manage things such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;receiving audio from Asterisk&lt;/li&gt;
&lt;li&gt;deciding when the caller has finished speaking&lt;/li&gt;
&lt;li&gt;sending audio to Faster-Whisper&lt;/li&gt;
&lt;li&gt;receiving the transcription&lt;/li&gt;
&lt;li&gt;maintaining conversation state&lt;/li&gt;
&lt;li&gt;sending the appropriate context to Qwen&lt;/li&gt;
&lt;li&gt;enforcing rules that should not be left to the language model&lt;/li&gt;
&lt;li&gt;sending the response to XTTS&lt;/li&gt;
&lt;li&gt;receiving generated speech&lt;/li&gt;
&lt;li&gt;handing that audio back to Asterisk&lt;/li&gt;
&lt;li&gt;managing errors and timeouts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last part is important.&lt;/p&gt;
&lt;p&gt;There are some things I do &lt;strong&gt;not&lt;/strong&gt; want to depend on the language model remembering.&lt;/p&gt;
&lt;p&gt;For example, the system is programmed to identify the caller and provide a recording disclosure.&lt;/p&gt;
&lt;p&gt;Those are deterministic application rules.&lt;/p&gt;
&lt;p&gt;The LLM can handle the conversation, but the application decides what absolutely has to happen.&lt;/p&gt;
&lt;p&gt;That separation turned out to be one of the more important lessons from the project.&lt;/p&gt;
&lt;h2&gt;Why I Needed More Than One Computer&lt;/h2&gt;
&lt;p&gt;Running a model is one thing.&lt;/p&gt;
&lt;p&gt;Running several models quickly enough to hold a telephone conversation is something else.&lt;/p&gt;
&lt;p&gt;Real-time voice has a deadline.&lt;/p&gt;
&lt;p&gt;If someone says something and your system takes fifteen seconds to answer, the technology may technically be working, but the conversation is not.&lt;/p&gt;
&lt;p&gt;Humans notice delay very quickly.&lt;/p&gt;
&lt;p&gt;The system currently spreads the workload across several machines.&lt;/p&gt;
&lt;p&gt;| Host | Role |
|---|---|
| &lt;code&gt;voicertr&lt;/code&gt; | Cisco ISR4351 handling the Xfinity/PSTN side |
| &lt;code&gt;astricks&lt;/code&gt; | Asterisk 20.6.0 |
| &lt;code&gt;ai&lt;/code&gt; | IVR orchestrator, Faster-Whisper, Ollama, and Qwen |
| &lt;code&gt;babyAI&lt;/code&gt; | Coqui XTTS-v2 speech generation using CUDA |&lt;/p&gt;
&lt;p&gt;This was not an attempt to build a cluster because clusters are cool.&lt;/p&gt;
&lt;p&gt;It happened because the workload demanded it.&lt;/p&gt;
&lt;p&gt;Speech recognition, LLM inference, and speech generation all have different compute characteristics. Once they start competing for the same CPU, GPU, memory, and storage resources, latency gets ugly very quickly.&lt;/p&gt;
&lt;p&gt;Splitting the workloads let me keep the conversation moving.&lt;/p&gt;
&lt;h2&gt;Speech-to-Text: Faster-Whisper&lt;/h2&gt;
&lt;p&gt;The first AI component sees the caller's audio.&lt;/p&gt;
&lt;p&gt;Faster-Whisper transcribes that audio into text.&lt;/p&gt;
&lt;p&gt;My current configuration uses the &lt;code&gt;tiny.en&lt;/code&gt; model with CPU inference and INT8 compute.&lt;/p&gt;
&lt;p&gt;That might sound like the least exciting part of the system, but speech recognition is where the whole thing can fall apart immediately.&lt;/p&gt;
&lt;p&gt;Telephone audio is not clean studio audio.&lt;/p&gt;
&lt;p&gt;There can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;background noise&lt;/li&gt;
&lt;li&gt;compression&lt;/li&gt;
&lt;li&gt;clipping&lt;/li&gt;
&lt;li&gt;accents&lt;/li&gt;
&lt;li&gt;people talking too quickly&lt;/li&gt;
&lt;li&gt;people mumbling&lt;/li&gt;
&lt;li&gt;people interrupting&lt;/li&gt;
&lt;li&gt;silence that may or may not actually mean the caller is done&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the transcription is wrong, everything after it is working with bad input.&lt;/p&gt;
&lt;p&gt;Garbage in, extremely confident AI garbage out.&lt;/p&gt;
&lt;h2&gt;The Language Model: Qwen Through Ollama&lt;/h2&gt;
&lt;p&gt;Once the caller's speech becomes text, the orchestrator sends the appropriate context to Qwen 3.5 9B through Ollama.&lt;/p&gt;
&lt;p&gt;The model generates the response text.&lt;/p&gt;
&lt;p&gt;This is where the conversational behavior lives.&lt;/p&gt;
&lt;p&gt;But I discovered pretty quickly that a telephone conversation is very different from a normal chatbot session.&lt;/p&gt;
&lt;p&gt;A chatbot can generate three paragraphs and nobody cares.&lt;/p&gt;
&lt;p&gt;A voice IVR that answers every question with three paragraphs becomes unbearable almost immediately.&lt;/p&gt;
&lt;p&gt;The responses need to be short.&lt;/p&gt;
&lt;p&gt;They need to sound conversational.&lt;/p&gt;
&lt;p&gt;They need to avoid rambling.&lt;/p&gt;
&lt;p&gt;And the system needs enough context to understand the conversation without feeding it an ever-growing wall of text on every turn.&lt;/p&gt;
&lt;p&gt;That is still one of the areas I continue to tune.&lt;/p&gt;
&lt;h2&gt;Text-to-Speech: Coqui XTTS-v2&lt;/h2&gt;
&lt;p&gt;Once Qwen generates a response, the text goes to Coqui XTTS-v2.&lt;/p&gt;
&lt;p&gt;XTTS turns the response into speech.&lt;/p&gt;
&lt;p&gt;This is running on a separate machine, &lt;code&gt;babyAI&lt;/code&gt;, using CUDA.&lt;/p&gt;
&lt;p&gt;And this is where I made a completely unnecessary but highly entertaining decision.&lt;/p&gt;
&lt;p&gt;I cloned a voice modeled after Duke Nukem.&lt;/p&gt;
&lt;p&gt;If you were around PC gaming in the 1990s, you probably know exactly the voice I mean.&lt;/p&gt;
&lt;p&gt;For anyone who does not: imagine every exaggerated action-movie hero rolled into one person, given a microphone, and then told subtlety was illegal.&lt;/p&gt;
&lt;p&gt;That was now my IVR.&lt;/p&gt;
&lt;h2&gt;And Then Rocket Mortgage Started Calling&lt;/h2&gt;
&lt;p&gt;Here is where the project became much more entertaining than I expected.&lt;/p&gt;
&lt;p&gt;I started getting repeated calls that appeared to be from Rocket Mortgage.&lt;/p&gt;
&lt;p&gt;I had not contacted them in years.&lt;/p&gt;
&lt;p&gt;My mortgage is not even through them.&lt;/p&gt;
&lt;p&gt;But the calls kept coming.&lt;/p&gt;
&lt;p&gt;Eventually one of those calls landed on the AI IVR.&lt;/p&gt;
&lt;p&gt;And the caller appeared to be an automated voice agent as well.&lt;/p&gt;
&lt;p&gt;So, without intending to, I had created:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI versus AI over the public telephone network.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My IVR was programmed to make sure it obtained the caller's name and provided the recording disclosure.&lt;/p&gt;
&lt;p&gt;That sounds simple.&lt;/p&gt;
&lt;p&gt;It is the sort of thing a human caller would barely notice.&lt;/p&gt;
&lt;p&gt;But the automated caller seemed to have its own expected conversational flow.&lt;/p&gt;
&lt;p&gt;At one point, my IVR asked for the caller's name in the middle of that flow.&lt;/p&gt;
&lt;p&gt;And that was apparently enough to confuse the other system.&lt;/p&gt;
&lt;p&gt;The conversation started going sideways.&lt;/p&gt;
&lt;p&gt;My AI wanted a name.&lt;/p&gt;
&lt;p&gt;The other system wanted to continue whatever script it was following.&lt;/p&gt;
&lt;p&gt;Neither side behaved exactly the way the other expected.&lt;/p&gt;
&lt;p&gt;And suddenly I was listening to two automated systems trying to negotiate control of a telephone conversation.&lt;/p&gt;
&lt;p&gt;One of them sounded like Duke Nukem.&lt;/p&gt;
&lt;p&gt;It was glorious.&lt;/p&gt;
&lt;h2&gt;When Two State Machines Walk Into a Phone Call&lt;/h2&gt;
&lt;p&gt;The funny part is that underneath the AI, there is a legitimate engineering lesson here.&lt;/p&gt;
&lt;p&gt;Conversational systems still have state.&lt;/p&gt;
&lt;p&gt;One system may expect something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;INTRODUCTION
    -&amp;gt;
SALES MESSAGE
    -&amp;gt;
QUESTION
    -&amp;gt;
EXPECTED RESPONSE
    -&amp;gt;
NEXT QUESTION
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;My system has its own state:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ANSWER CALL
    -&amp;gt;
PROVIDE DISCLOSURE
    -&amp;gt;
IDENTIFY CALLER
    -&amp;gt;
LISTEN
    -&amp;gt;
TRANSCRIBE
    -&amp;gt;
GENERATE RESPONSE
    -&amp;gt;
SPEAK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now put those two systems on the same telephone call.&lt;/p&gt;
&lt;p&gt;Each one has goals.&lt;/p&gt;
&lt;p&gt;Each one has assumptions about turn-taking.&lt;/p&gt;
&lt;p&gt;Each one may be waiting for a specific kind of response.&lt;/p&gt;
&lt;p&gt;Each one may have timeout rules.&lt;/p&gt;
&lt;p&gt;Each one may attempt to recover when the conversation does something unexpected.&lt;/p&gt;
&lt;p&gt;A human can usually handle an interruption such as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;"Before we continue, what is your name?"&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another automated agent may not.&lt;/p&gt;
&lt;p&gt;That is exactly what made the call so interesting.&lt;/p&gt;
&lt;p&gt;It was not simply two language models having a conversation.&lt;/p&gt;
&lt;p&gt;It was two complete conversational systems, each with its own logic and expectations, colliding over a normal telephone call.&lt;/p&gt;
&lt;h2&gt;The Hard Part Is Latency&lt;/h2&gt;
&lt;p&gt;One of the biggest lessons from the project has been that conversational AI is not just about model quality.&lt;/p&gt;
&lt;p&gt;It is about time.&lt;/p&gt;
&lt;p&gt;The complete path looks roughly like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Caller speaks
    |
    v
Detect end of speech
    |
    v
Transcribe audio
    |
    v
Generate LLM response
    |
    v
Generate speech
    |
    v
Send audio back through Asterisk
    |
    v
Caller hears response
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Every stage adds latency.&lt;/p&gt;
&lt;p&gt;Even if every individual component is "fast," the delays add together.&lt;/p&gt;
&lt;p&gt;There is also a difference between:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The model can run on this computer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The model can run fast enough on this computer to participate in a telephone conversation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Those are not the same requirement.&lt;/p&gt;
&lt;p&gt;This is one of the main reasons I ended up distributing the workload.&lt;/p&gt;
&lt;h2&gt;Things That Do Not Work Perfectly&lt;/h2&gt;
&lt;p&gt;This project has also been a reminder that demos are easy and systems are hard.&lt;/p&gt;
&lt;p&gt;There are plenty of edge cases.&lt;/p&gt;
&lt;p&gt;A few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the caller talks over the AI&lt;/li&gt;
&lt;li&gt;speech detection decides the caller is finished when they are not&lt;/li&gt;
&lt;li&gt;Whisper mishears a word&lt;/li&gt;
&lt;li&gt;the LLM generates too much text&lt;/li&gt;
&lt;li&gt;TTS takes too long&lt;/li&gt;
&lt;li&gt;audio levels are wrong&lt;/li&gt;
&lt;li&gt;background noise creates nonsense transcription&lt;/li&gt;
&lt;li&gt;one model consumes resources another model needs&lt;/li&gt;
&lt;li&gt;the caller says something completely outside the expected flow&lt;/li&gt;
&lt;li&gt;the LLM gives a response that sounds fine in text but terrible when spoken aloud&lt;/li&gt;
&lt;li&gt;silence lasts just long enough to make the system wonder whether the call is over&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these problems are individually shocking.&lt;/p&gt;
&lt;p&gt;The interesting part is that they all happen in the same pipeline.&lt;/p&gt;
&lt;h2&gt;The Old Stuff Still Matters&lt;/h2&gt;
&lt;p&gt;One of the things I enjoyed most about this project was getting back into voice.&lt;/p&gt;
&lt;p&gt;It also reminded me that modern AI does not replace traditional infrastructure knowledge.&lt;/p&gt;
&lt;p&gt;You still need to understand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FXO&lt;/li&gt;
&lt;li&gt;SIP&lt;/li&gt;
&lt;li&gt;RTP&lt;/li&gt;
&lt;li&gt;codecs&lt;/li&gt;
&lt;li&gt;Asterisk&lt;/li&gt;
&lt;li&gt;routing&lt;/li&gt;
&lt;li&gt;Linux&lt;/li&gt;
&lt;li&gt;application state&lt;/li&gt;
&lt;li&gt;audio handling&lt;/li&gt;
&lt;li&gt;networking&lt;/li&gt;
&lt;li&gt;CPU and GPU resource constraints&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The AI models are only one part of the system.&lt;/p&gt;
&lt;p&gt;If the SIP trunk is broken, Qwen cannot save you.&lt;/p&gt;
&lt;p&gt;If the FXO interface is not working, Whisper is irrelevant.&lt;/p&gt;
&lt;p&gt;If Asterisk cannot move the audio correctly, your fancy cloned voice is just a very expensive WAV file sitting on disk.&lt;/p&gt;
&lt;p&gt;That is probably what I like most about the project.&lt;/p&gt;
&lt;p&gt;It crosses a lot of different areas.&lt;/p&gt;
&lt;p&gt;Old-school telephony.&lt;/p&gt;
&lt;p&gt;Networking.&lt;/p&gt;
&lt;p&gt;Linux.&lt;/p&gt;
&lt;p&gt;Python.&lt;/p&gt;
&lt;p&gt;Local AI.&lt;/p&gt;
&lt;p&gt;GPUs.&lt;/p&gt;
&lt;p&gt;Speech recognition.&lt;/p&gt;
&lt;p&gt;Voice cloning.&lt;/p&gt;
&lt;p&gt;And just enough ridiculousness to make the entire thing worth building.&lt;/p&gt;
&lt;h2&gt;So What Did I Actually Build?&lt;/h2&gt;
&lt;p&gt;In the end, this is not just a chatbot connected to a telephone.&lt;/p&gt;
&lt;p&gt;It is a complete real-time voice pipeline:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;PSTN
  -&amp;gt;
FXO
  -&amp;gt;
SIP
  -&amp;gt;
Asterisk
  -&amp;gt;
Application Logic
  -&amp;gt;
Speech Recognition
  -&amp;gt;
Language Model
  -&amp;gt;
Speech Synthesis
  -&amp;gt;
Asterisk
  -&amp;gt;
PSTN
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And every part of that chain has to work quickly enough that the person on the other end still believes they are participating in a conversation.&lt;/p&gt;
&lt;p&gt;The fact that another AI eventually called it was just a bonus.&lt;/p&gt;
&lt;p&gt;The fact that the other AI got confused by mine asking its name was even better.&lt;/p&gt;
&lt;p&gt;And the fact that the whole conversation happened in a cloned Duke Nukem-style voice?&lt;/p&gt;
&lt;p&gt;That was just good engineering judgment.&lt;/p&gt;
&lt;p&gt;Probably.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;This post describes my own lab setup and my observations of calls received by the system. References to third-party companies or automated callers describe what I observed during those calls and are not claims about the internal design of those companies' systems.&lt;/em&gt;&lt;/p&gt;</content><category term="Technology"/><category term="AI"/><category term="IVR"/><category term="Asterisk"/><category term="Cisco"/><category term="SIP"/><category term="Voice AI"/><category term="Faster-Whisper"/><category term="Qwen"/><category term="Ollama"/><category term="Coqui XTTS"/><category term="Networking"/><category term="Telephony"/></entry><entry><title>Falling Asleep to Flying Toasters</title><link href="/falling-asleep-to-flying-toasters.html" rel="alternate"/><published>2025-12-20T00:00:00-08:00</published><updated>2025-12-20T00:00:00-08:00</updated><author><name>NuX</name></author><id>tag:None,2025-12-20:/falling-asleep-to-flying-toasters.html</id><summary type="html">&lt;p&gt;A nostalgic dive into Berkeley Systems’ After Dark screen savers, from Flying Toasters to Totally Twisted, and the unexpected journey of getting them running again, poking at their files, and capturing their assets decades later.&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Falling Asleep to Flying Toasters&lt;/h1&gt;
&lt;p&gt;You know, screen savers used to actually matter.&lt;/p&gt;
&lt;p&gt;I don’t mean “this looks cool while I’m away from my desk.” I mean they had a job. CRTs would burn images into the phosphor if you left something up too long. So you needed motion. Constant motion.&lt;/p&gt;
&lt;p&gt;And somewhere along the way, someone decided that if things had to move anyway, they might as well be weird.&lt;/p&gt;
&lt;p&gt;That’s how we ended up with screen savers that weren’t just background noise, but little moments. Stuff you noticed. Stuff you remembered.&lt;/p&gt;
&lt;h2&gt;The After Dark Era&lt;/h2&gt;
&lt;p&gt;If you had a PC in the 90s, there’s a decent chance After Dark was installed on it. Even if you don’t remember the name, you remember the visuals.&lt;/p&gt;
&lt;p&gt;Flying Toasters are the obvious one. They’re practically shorthand for “old computer.” Chrome toasters with wings just casually floating by like that was a totally normal thing to see on an office machine.&lt;/p&gt;
&lt;p&gt;But honestly, those were just the friendly ones.&lt;/p&gt;
&lt;h2&gt;Totally Twisted Was Something Else&lt;/h2&gt;
&lt;p&gt;The ones that stuck with me came from Totally Twisted After Dark.&lt;/p&gt;
&lt;p&gt;I saw it running on a friend’s PC and immediately realized this wasn’t passive entertainment. Some of these screen savers wanted you involved. Others just wanted to see how uncomfortable they could make you while still technically being allowed.&lt;/p&gt;
&lt;p&gt;There was one where people bungee-jumped from the top of the screen. Most of the time it was fine. And then sometimes… it wasn’t. Cord snaps. Splat. End of story.&lt;/p&gt;
&lt;p&gt;Another one turned the screen into a shooting gallery. Crosshairs, ammo, mimes everywhere. It was a screen saver that dared you to touch the mouse.&lt;/p&gt;
&lt;p&gt;And then there was the old man.&lt;/p&gt;
&lt;p&gt;If you know, you know.&lt;/p&gt;
&lt;p&gt;He walks across the screen in a trench coat, muttering at you. Laughing to himself. Saying things that feel like they shouldn’t be directed at a computer user. Then he stops, turns toward you, and asks if you want to know what time it is.&lt;/p&gt;
&lt;p&gt;You do.&lt;/p&gt;
&lt;p&gt;He opens the coat. He’s naked. Except he isn’t, because there’s a big clock covering exactly what it needs to cover. He sways back and forth and the clock moves with him, perfectly timed.&lt;/p&gt;
&lt;p&gt;It’s dumb. It’s juvenile. It’s absolutely ridiculous.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Falling asleep to flying toasters" src="/images/fallingAsleepWithToasters.png"&gt;&lt;/p&gt;
&lt;p&gt;And it made me laugh way harder than it should have.&lt;/p&gt;
&lt;p&gt;Still does, honestly.&lt;/p&gt;
&lt;h2&gt;Fast Forward a Few Decades&lt;/h2&gt;
&lt;p&gt;Like most things, that era got boxed up by life.&lt;/p&gt;
&lt;p&gt;Work happened. Kids happened. Time disappeared. At some point I bought the original CD, mostly out of nostalgia, knowing full well it probably wouldn’t run anymore.&lt;/p&gt;
&lt;p&gt;It didn’t.&lt;/p&gt;
&lt;p&gt;And for a long time, that was fine. It sat on a shelf like a little time capsule I didn’t have time to open.&lt;/p&gt;
&lt;p&gt;Then the house got quieter. Kids moved out. Time showed up again.&lt;/p&gt;
&lt;p&gt;And that old thought came back: I kind of want to see how this thing actually works.&lt;/p&gt;
&lt;h2&gt;Step One: Make It Run&lt;/h2&gt;
&lt;p&gt;My first instinct was to spin up Windows 95 in a VM. Easy enough, right?&lt;/p&gt;
&lt;p&gt;I got the startup sound, which immediately sent me back to fixing PCs for a school district. That part was great.&lt;/p&gt;
&lt;p&gt;The rest… not so much.&lt;/p&gt;
&lt;p&gt;Crashes. Missing DLLs. Blue screens. Rebuild after rebuild, same weird behavior. I tried different ISOs, different configs, and kept getting the same results.&lt;/p&gt;
&lt;p&gt;Eventually it clicked that nothing was corrupted. The machine was just too fast.&lt;/p&gt;
&lt;p&gt;Modern CPUs don’t just outperform old ones — they break assumptions. Timing loops, delays, things that were never meant to run at gigahertz speeds just fall apart.&lt;/p&gt;
&lt;h2&gt;Slowing Time Down&lt;/h2&gt;
&lt;p&gt;That’s where 86Box came in.&lt;/p&gt;
&lt;p&gt;I set it up with what felt right without really thinking about it too hard. Pentium II. A couple hundred megahertz. Enough memory to be generous, but not ridiculous.&lt;/p&gt;
&lt;p&gt;And suddenly Windows 95 behaved like it remembered who it was.&lt;/p&gt;
&lt;p&gt;Totally Twisted installed cleanly. The screen savers ran. Everything worked.&lt;/p&gt;
&lt;p&gt;Which is where curiosity officially took over.&lt;/p&gt;
&lt;h2&gt;Poking at the Files&lt;/h2&gt;
&lt;p&gt;After Dark’s setup is pretty clever. There’s an engine, and then there are these &lt;code&gt;.AD&lt;/code&gt; files that hold each individual screen saver.&lt;/p&gt;
&lt;p&gt;Naturally, I assumed those files were packed with sprites and sounds in some extractable format.&lt;/p&gt;
&lt;p&gt;So I did what anyone would do first — I tried the obvious tools. Resource editors. Resource Hacker. The usual stuff that cracks open a DLL and spills out bitmaps and WAVs like candy.&lt;/p&gt;
&lt;p&gt;Nothing.&lt;/p&gt;
&lt;p&gt;No images. No audio. No friendly resource tables. Not even junk that looked like it wanted to be something.&lt;/p&gt;
&lt;p&gt;At that point I backed up and asked a simpler question: what are these files, really?&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;file&lt;/code&gt; on Linux made things clearer. These weren’t modern PE DLLs at all — they identified as NE executables, old 16-bit Windows–era files. Windows 3.x territory. That explained why modern tools were shrugging.&lt;/p&gt;
&lt;p&gt;What surprised me was that even tools from that era didn’t help. NE-aware resource viewers still came up empty. No bitmaps. No WAV resources. No candy spilled out at all.&lt;/p&gt;
&lt;p&gt;That’s when it really set in: these &lt;code&gt;.AD&lt;/code&gt; files weren’t storing assets the traditional Windows way — not then, and not now.&lt;/p&gt;
&lt;p&gt;So I stopped treating them like executables and started treating them like raw data.&lt;/p&gt;
&lt;h2&gt;When in Doubt, Use Strings&lt;/h2&gt;
&lt;p&gt;I ran &lt;code&gt;strings&lt;/code&gt; across the files just to see what was in there.&lt;/p&gt;
&lt;p&gt;And buried in the noise were familiar markers. RIFF. WAVE.&lt;/p&gt;
&lt;p&gt;That was enough.&lt;/p&gt;
&lt;p&gt;Once I had offsets, &lt;code&gt;dd&lt;/code&gt; did the rest. No loaders. No emulation. Just raw bytes pulled straight out of the file.&lt;/p&gt;
&lt;p&gt;And sure enough, clean WAV audio dropped out the other side.&lt;/p&gt;
&lt;p&gt;That alone told me these files weren’t using anything like standard Windows resource storage. Whatever Berkeley Systems did here, it was custom.&lt;/p&gt;
&lt;h2&gt;Sprites Were Another Story&lt;/h2&gt;
&lt;p&gt;The visuals didn’t give themselves up so easily.&lt;/p&gt;
&lt;p&gt;I couldn’t find anything obvious to carve out, which suggests the drawing was happening programmatically, or at least in a format that never expected to be seen outside the engine.&lt;/p&gt;
&lt;p&gt;So instead of extracting them, I watched them.&lt;/p&gt;
&lt;p&gt;I ended up writing a small custom application whose only job was to take pictures. No fancy automation, no deep hooks — just a way to capture frames coming off a running system reliably.&lt;/p&gt;
&lt;p&gt;Frame by frame. Slow. Manual in the very literal sense — stitching individual sprite cells back together by hand after capture, making sure timing and alignment still felt right.&lt;/p&gt;
&lt;p&gt;But it worked.&lt;/p&gt;
&lt;h2&gt;Closing the Loop&lt;/h2&gt;
&lt;p&gt;Once I had audio and visuals, it felt wrong to just leave them sitting in a folder.&lt;/p&gt;
&lt;p&gt;So I wrote a very basic screen saver in VB.NET. Nothing ambitious. Just enough to display what I’d recovered and hear those sounds again without needing the original engine.&lt;/p&gt;
&lt;p&gt;Seeing it all move again — disconnected from where it started, but still recognizable — felt like finishing something I’d left hanging years ago.&lt;/p&gt;
&lt;h2&gt;Why I Even Bothered&lt;/h2&gt;
&lt;p&gt;This wasn’t about cracking software or proving anything.&lt;/p&gt;
&lt;p&gt;It was curiosity. And nostalgia. And wanting to understand how people snuck humor into places where no one was really supposed to be watching.&lt;/p&gt;
&lt;p&gt;Screen savers were never meant to be serious.&lt;/p&gt;
&lt;p&gt;And maybe that’s why they stuck with me.&lt;/p&gt;</content><category term="Technology"/><category term="nostalgia"/><category term="screen savers"/><category term="windows 95"/><category term="tinkering"/><category term="Linux"/></entry><entry><title>A Bad Workman Blames His Tools</title><link href="/bad-workman-blames-his-tools.html" rel="alternate"/><published>2025-11-03T00:00:00-08:00</published><updated>2025-11-03T00:00:00-08:00</updated><author><name>NuX</name></author><id>tag:None,2025-11-03:/bad-workman-blames-his-tools.html</id><summary type="html">&lt;p&gt;A deeper look at a simple proverb — and how it still calls out the habit of shifting blame instead of owning the work.&lt;/p&gt;</summary><content type="html">&lt;hr&gt;
&lt;p&gt;For a while now, this old proverb has been stuck in my head:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A bad workman blames his tools.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s one of those lines that sounds like something your grandfather might say, but the older you get, the truer it becomes.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;The Meeting That Sparked It&lt;/h3&gt;
&lt;p&gt;It happened during a logistics meeting. I was there for technical reasons — we’re preparing for what I’ve been calling a &lt;strong&gt;heart transplant&lt;/strong&gt;, replacing our core systems. The talk was all about the new gear, timelines, migration paths — everything shiny and forward-looking.  &lt;/p&gt;
&lt;p&gt;Then I asked a simple question:  &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Have we thought about transporting the old equipment from the rented data centers back to one of our facilities?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The room went quiet for a moment. Then the manager — can’t really say “leader” — replied:  &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Why didn’t you say that earlier?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And there it was — that familiar feeling of the spotlight turning your way, as if responsibility suddenly shifted to you for something everyone else missed.&lt;/p&gt;
&lt;p&gt;I don’t mind owning mistakes when they’re mine, but this one wasn’t. The budgets were locked. The plans approved. Yet somehow, I was the convenient target.  &lt;/p&gt;
&lt;p&gt;That’s when the proverb came back to me — sharp and clear.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;What the Proverb Really Means&lt;/h3&gt;
&lt;p&gt;The line dates back centuries. Originally, it referred to craftsmen who blamed their hammers or chisels when their work went wrong — instead of admitting they hadn’t mastered their craft.&lt;/p&gt;
&lt;p&gt;In tech or leadership, the tools just look different: servers, scripts, dashboards, or people. But the habit is the same — to push the fault somewhere else.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;technician&lt;/strong&gt; might blame the software or hardware.  &lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;manager&lt;/strong&gt; might blame their team.  &lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;leader&lt;/strong&gt; might blame the system or “circumstances.”  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But in every case, it’s a way of avoiding reflection.&lt;/p&gt;
&lt;p&gt;Good workmen — and good leaders — look inward first. They ask, &lt;em&gt;What could I have done differently?&lt;/em&gt; They sharpen the tools, train the people, or fix the process. They don’t hide behind excuses.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Reflection Over Deflection&lt;/h3&gt;
&lt;p&gt;Leadership isn’t about having all the answers; it’s about taking responsibility for finding them.  &lt;/p&gt;
&lt;p&gt;When something goes sideways, it’s easy to look for a place to land the blame. But integrity means owning your slice of it — even when it’s uncomfortable.&lt;/p&gt;
&lt;p&gt;So whether you’re leading a team or tightening bolts on the floor, remember the old line. It’s lasted this long because it’s true:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A bad workman blames his tools.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And maybe, for our modern world:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A good leader sharpens them.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;— NuX | BlogByNuX&lt;/em&gt;&lt;/p&gt;</content><category term="Leadership"/><category term="leadership"/><category term="reflection"/><category term="accountability"/><category term="culture"/></entry><entry><title>Dave — A Masterclass in Leadership</title><link href="/dave-masterclass-leadership.html" rel="alternate"/><published>2025-08-11T00:00:00-07:00</published><updated>2025-08-11T00:00:00-07:00</updated><author><name>NuXology</name></author><id>tag:None,2025-08-11:/dave-masterclass-leadership.html</id><summary type="html">&lt;p&gt;A personal reflection on working with Dave — a leader who made an impression that’s still teaching me things years later.&lt;/p&gt;</summary><content type="html">&lt;p&gt;When I first crossed paths with Dave, we were both new hires — him stepping in as the supervisor, me coming on as the Network Engineer. It didn’t take long before I started noticing how he handled things. I’d catch myself watching, almost without meaning to, like leaning toward a porch light on a summer night without thinking about it.&lt;/p&gt;
&lt;p&gt;I never asked where he picked it up, and maybe it didn’t matter. Whatever the case, Dave made leadership feel natural — like it was just part of who he was. He knew the big ideas, like Maslow’s Hierarchy of Needs, but it never felt like a lecture. He’d just work it into the moment, and you’d find yourself thinking, &lt;em&gt;“Huh… that actually makes sense.”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Same thing with the Myers-Briggs personality types. He never pulled out a form or made us take a quiz. It was more like he kept a mental notebook, using it quietly to figure out how people ticked and what might help them get unstuck.&lt;/p&gt;
&lt;p&gt;Even when he moved higher up the ladder, he didn’t vanish behind a wall of meetings. If you sent him a message, he got back to you. If you were drifting, he’d toss you a quick word or two to get you back on track.&lt;/p&gt;
&lt;p&gt;Looking back now, I realize a lot of what I know about motivating people came from him — not in big “training moments,” but in little things I picked up along the way. He showed me that meeting people where they are isn’t just about patience. It’s about respect, and it’s where real progress starts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ode to Dave:&lt;/strong&gt; Here’s to the leader who taught by example, inspired through action, and left a lasting mark on those fortunate enough to work alongside him.&lt;/p&gt;</content><category term="Leadership"/><category term="leadership"/><category term="mentorship"/><category term="inspiration"/><category term="personal-growth"/></entry><entry><title>Why SSH Works from Windows but Not Ubuntu in Proxmox + GNS3</title><link href="/ssh-windows-ubuntu-proxmox-gns3.html" rel="alternate"/><published>2025-08-05T00:00:00-07:00</published><updated>2025-08-05T00:00:00-07:00</updated><author><name>NuX</name></author><id>tag:None,2025-08-05:/ssh-windows-ubuntu-proxmox-gns3.html</id><summary type="html">&lt;p&gt;Debugging an odd case where Ubuntu in Proxmox could ping a GNS3 router but not SSH to it — while Windows worked fine.&lt;/p&gt;</summary><content type="html">&lt;h2&gt;The Symptom&lt;/h2&gt;
&lt;p&gt;I ran into a strange issue while labbing in &lt;strong&gt;Proxmox&lt;/strong&gt; with &lt;strong&gt;GNS3&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows&lt;/strong&gt; (bare metal) could SSH to my GNS3 router without a problem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ubuntu&lt;/strong&gt; (running as a VM in Proxmox) could &lt;code&gt;ping&lt;/code&gt; the router but &lt;strong&gt;SSH timed out&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Both were on the same subnet and connected to the same Proxmox bridge (&lt;code&gt;vmbr0&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At first glance, this made no sense. Ping worked, so Layer 3 was fine — why not TCP/22?&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;First Clues&lt;/h2&gt;
&lt;p&gt;Inside the Ubuntu VM:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ip&lt;span class="w"&gt; &lt;/span&gt;neigh&lt;span class="w"&gt; &lt;/span&gt;show
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;showed correct ARP resolution for the router’s MAC.&lt;/p&gt;
&lt;p&gt;A Wireshark capture on the GNS3 side revealed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ubuntu’s TCP SYN packets &lt;strong&gt;arrived&lt;/strong&gt; at the router.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No SYN/ACK reply&lt;/strong&gt; was sent back.&lt;/li&gt;
&lt;li&gt;Instead, &lt;code&gt;debug ip tcp transactions&lt;/code&gt; on the Cisco router showed:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;TCP&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;checksum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mf"&gt;192.168&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;2.233&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;XXXXX&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mf"&gt;192.168&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;2.136&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That was the smoking gun.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;The Cause: TX Checksum Offload&lt;/h2&gt;
&lt;p&gt;The problem turned out to be &lt;strong&gt;TCP checksum offloading&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modern NIC drivers (including Proxmox’s virtio) sometimes leave the TCP checksum unset, expecting the physical NIC to fill it in before sending.&lt;/li&gt;
&lt;li&gt;In GNS3, the virtual router sees the raw packet &lt;em&gt;before&lt;/em&gt; a real NIC ever touches it, so the checksum is wrong.&lt;/li&gt;
&lt;li&gt;Windows’ NIC/driver stack handled this differently, so it never showed the problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ubuntu’s NIC (&lt;code&gt;ens18&lt;/code&gt;) was sending packets with invalid checksums to the router, so IOS dropped them instantly.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;The Fix (Quick)&lt;/h2&gt;
&lt;p&gt;Disable TX checksum offload in Ubuntu:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;ethtool&lt;span class="w"&gt; &lt;/span&gt;-K&lt;span class="w"&gt; &lt;/span&gt;ens18&lt;span class="w"&gt; &lt;/span&gt;tx&lt;span class="w"&gt; &lt;/span&gt;off
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Test SSH again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh&lt;span class="w"&gt; &lt;/span&gt;admin@192.168.2.136
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It should now connect without issue.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;The Fix (Persistent)&lt;/h2&gt;
&lt;p&gt;Since Ubuntu now uses &lt;strong&gt;Netplan&lt;/strong&gt; instead of &lt;code&gt;/etc/network/interfaces&lt;/code&gt;, you can’t just add &lt;code&gt;post-up&lt;/code&gt; lines.&lt;br&gt;
The easiest persistent fix is a &lt;strong&gt;systemd service&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/systemd/system/disable-tx-offload.service&lt;/span&gt;
&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Disable TX Checksum Offload on ens18&lt;/span&gt;
&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network.target&lt;/span&gt;

&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;oneshot&lt;/span&gt;
&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/sbin/ethtool -K ens18 tx off&lt;/span&gt;

&lt;span class="k"&gt;[Install]&lt;/span&gt;
&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Enable it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;daemon-reload
sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;disable-tx-offload.service
sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;disable-tx-offload.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Verify:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ethtool&lt;span class="w"&gt; &lt;/span&gt;-k&lt;span class="w"&gt; &lt;/span&gt;ens18&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;tx-checksumming
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It should read &lt;code&gt;off&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If you can &lt;strong&gt;ping but not SSH&lt;/strong&gt; from a Proxmox VM to a GNS3 router, check for &lt;strong&gt;TCP checksum failures&lt;/strong&gt; in IOS debug.&lt;/li&gt;
&lt;li&gt;In GNS3 environments, checksum offload can break traffic to virtual devices.&lt;/li&gt;
&lt;li&gt;Disabling TX checksum offload on the VM NIC is a safe workaround in lab setups.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Have you run into similar odd networking issues between Proxmox and GNS3?&lt;/strong&gt;&lt;br&gt;
Drop a comment — this one took a while to nail down.&lt;/p&gt;</content><category term="Networking"/><category term="Proxmox"/><category term="GNS3"/><category term="Ubuntu"/><category term="TCP"/><category term="Checksum Offload"/><category term="Troubleshooting"/></entry><entry><title>Occam’s Razor in the Real World: A Monday Morning Mystery</title><link href="/occams-razor-firewall-classification.html" rel="alternate"/><published>2025-04-09T00:00:00-07:00</published><updated>2025-04-09T00:00:00-07:00</updated><author><name>BlogByNux</name></author><id>tag:None,2025-04-09:/occams-razor-firewall-classification.html</id><summary type="html">&lt;p&gt;A real-world tale of Monday morning troubleshooting, rising tickets, and a reminder that the simplest explanation is often hidden behind a trusted system update.&lt;/p&gt;</summary><content type="html">&lt;hr&gt;
&lt;p&gt;It was a bright, beautiful Monday morning. All was quiet in the land… &lt;em&gt;too&lt;/em&gt; quiet.&lt;/p&gt;
&lt;p&gt;Since I take Fridays off, Monday mornings are my time to reacquaint myself with the monitoring tools—make sure everything’s still humming along. But this Monday, the silence was broken by a rising tide of tickets flowing into the “network” queue:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Google Search isn’t working.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s never a good start to the week.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;The First Signs&lt;/h2&gt;
&lt;p&gt;As I began investigating, the volume of tickets kept increasing. A few minutes later, I got a call from the Manager who shared something interesting: this all &lt;em&gt;might&lt;/em&gt; have started on Friday. He added me to a chat thread where the Friday coverage team had been discussing some strange behavior. &lt;/p&gt;
&lt;p&gt;Reading through the conversation, I saw a lot of theories flying around—some complex, some wild. But one thing jumped out at me:&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Occam’s Razor&lt;/strong&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The simplest explanation is often the correct one.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;Clue in the Firewall Logs&lt;/h2&gt;
&lt;p&gt;I tried reproducing the issue—and succeeded. Google Search was unresponsive. DNS resolution? Fine. Internet access? Working. But something felt off.&lt;/p&gt;
&lt;p&gt;I checked the firewall, and that’s where the mystery unraveled: &lt;strong&gt;traffic to Google was being denied.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Digging deeper, I found the culprit.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;When "Google" Becomes a Game&lt;/h2&gt;
&lt;p&gt;The firewall's &lt;strong&gt;definition update service&lt;/strong&gt; had pushed a change that &lt;strong&gt;reclassified the application "google"&lt;/strong&gt;. Specifically, it tagged &lt;code&gt;doodles.google&lt;/code&gt; more restrictive &lt;strong&gt;category&lt;/strong&gt;—one typically associated with &lt;strong&gt;games or high-risk entertainment content&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That meant, thanks to automated policy enforcement, outbound access to Google’s search services was now &lt;strong&gt;blocked by default&lt;/strong&gt; under our existing rule set.&lt;/p&gt;
&lt;p&gt;No one had manually touched the firewall rules. It was just a subtle classification change that quietly broke a critical service.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;A Razor Sharp Reminder&lt;/h2&gt;
&lt;p&gt;So no, it wasn’t DNS. It wasn’t our upstream provider. It wasn’t some exotic zero-day.&lt;/p&gt;
&lt;p&gt;It was a &lt;strong&gt;simple classification update&lt;/strong&gt; and a security policy doing exactly what it was configured to do—with unintended consequences.&lt;/p&gt;
&lt;h3&gt;Occam’s Razor wins again.&lt;/h3&gt;
&lt;p&gt;Start simple. Don’t assume conspiracy when configuration is enough.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;🔍 &lt;strong&gt;Takeaway:&lt;/strong&gt;&lt;br&gt;
When troubleshooting, especially on a Monday, don’t ignore the basics. Automated tools are powerful, but not infallible. Sometimes, the simplest answer is just hiding behind a quiet update.&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="Networking"/><category term="troubleshooting"/><category term="networking"/><category term="occams razor"/><category term="firewall"/><category term="sysadmin"/><category term="real-story"/></entry><entry><title>Automating the Download of Old Time Radio Shows with XOJO</title><link href="/automating-otr-downloads-xojo.html" rel="alternate"/><published>2025-01-05T00:00:00-08:00</published><updated>2025-01-05T00:00:00-08:00</updated><author><name>BlogByNuX</name></author><id>tag:None,2025-01-05:/automating-otr-downloads-xojo.html</id><summary type="html">&lt;p&gt;A look at creating a downloader for Old Time Radio shows using XOJO.&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Automating the Download of Old Time Radio Shows with XOJO&lt;/h1&gt;
&lt;h2&gt;Growing Up Out of Era&lt;/h2&gt;
&lt;p&gt;When I was young, I remember when Old Time Radio (OTR) was on the local radio station every weekend. 
Listening to the best like "The George Burns and Gracie Allen Show," "Yours Truly Johnny Dollar," 
and "The Shadow," to name a few. These programs captured the imagination of listeners across generations.&lt;/p&gt;
&lt;p&gt;Well, I stumbled across a website a while back that had backed up some OTR shows in MP3 format. I thought to grab a couple, but with style. 
That’s when I decided to create a basic downloader for these using a language called &lt;strong&gt;XOJO&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;The Idea&lt;/h2&gt;
&lt;p&gt;The idea was simple:
1. Parse the website's HTML to extract all MP3 links.
2. Decode the filenames from their URL-encoded form (like &lt;code&gt;%20&lt;/code&gt; into spaces).
3. Save the MP3 files into a neatly organized folder.
4. Add error handling and a clean user interface for selecting a folder and initiating the download.&lt;/p&gt;
&lt;h2&gt;Building the &lt;code&gt;DownloadManager&lt;/code&gt; Class in XOJO&lt;/h2&gt;
&lt;p&gt;To streamline downloading files in our application, we created a versatile &lt;code&gt;DownloadManager&lt;/code&gt; class in XOJO. This class handles file downloads using XOJO's &lt;code&gt;URLConnection&lt;/code&gt; and ensures files are saved seamlessly to the destination folder specified during initialization.&lt;/p&gt;
&lt;p&gt;The class includes:
1. &lt;strong&gt;A Constructor&lt;/strong&gt; to initialize the destination folder:&lt;/p&gt;
&lt;pre&gt;&lt;code class="code"&gt;

   Public Sub Constructor(destinationFile As FolderItem)
       Self.DestinationFile = destinationFile
   End Sub
Public Sub StartDownload(fileURL As String)
    Try
        ' Set request headers (optional)
        Me.RequestHeader("Accept") = "*/*"

        ' Send the request and save the file to the destination folder
        Me.Send("GET", fileURL, DestinationFile)
    Catch e As IOException
        MessageBox("Failed to download: " + fileURL)
    End Try
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Why Use &lt;code&gt;DownloadManager&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;This approach encapsulates download functionality in a reusable class, making it easier to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Handle downloads in a structured and error-resilient manner.&lt;/li&gt;
&lt;li&gt;Extend the functionality (e.g., logging, retries, or progress tracking).&lt;/li&gt;
&lt;li&gt;Integrate seamlessly into larger projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Why XOJO?&lt;/h2&gt;
&lt;p&gt;XOJO is a fantastic tool for developing cross-platform applications quickly. Its straightforward syntax and powerful built-in libraries made it easy to handle tasks like HTTP requests and file management.&lt;/p&gt;
&lt;h2&gt;Learn More&lt;/h2&gt;
&lt;p&gt;The full source code and documentation for the downloader are available on &lt;a href="https://github.com/CodeByNuX/XojoSnatch"&gt;GitHub&lt;/a&gt;. Feel free to explore and contribute!&lt;/p&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;This project combined nostalgia with modern technology, allowing me to preserve and enjoy these classic shows in a unique way. Whether you're an OTR enthusiast or just exploring XOJO, I hope this inspires you to create something of your own.&lt;/p&gt;
&lt;p&gt;Happy Coding!&lt;/p&gt;</content><category term="Technology"/><category term="XOJO"/><category term="Old Time Radio"/><category term="Programming"/><category term="Nostalgia"/></entry><entry><title>Mastering the Network: Seeing the Full Picture in Troubleshooting</title><link href="/mastering-network-troubleshooting.html" rel="alternate"/><published>2024-12-17T00:00:00-08:00</published><updated>2024-12-17T00:00:00-08:00</updated><author><name>BlogByNuX</name></author><id>tag:None,2024-12-17:/mastering-network-troubleshooting.html</id><summary type="html">&lt;p&gt;Exploring the parallels between a classic parable and modern network troubleshooting, this post delves into the importance of overcoming biases and employing structured approaches to effectively manage network issues.&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;In the world of network troubleshooting, perspectives can greatly influence outcomes—much like the well-known parable of the three blind men and the elephant. This story tells of three blind men who encounter an elephant for the first time, each touching a different part of the animal. One feels the trunk and declares the elephant is like a snake; another touches a leg and says it's like a tree; the third feels the side and insists it's like a wall. Each man, limited by his direct experience, believes he understands the whole elephant. Yet, none of them has the complete picture.&lt;/p&gt;
&lt;p&gt;&lt;img alt="parable of the three blind men and the elephant" src="images/elephant.jpg"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;The Role of Bias in Network Troubleshooting&lt;/h1&gt;
&lt;p&gt;In troubleshooting, just as in the parable, personal experience and inherent biases can cloud our judgment. &lt;strong&gt;Confirmation bias&lt;/strong&gt; leads us to favor solutions that align with our past experiences, potentially overlooking novel fixes or underestimating emerging issues. &lt;strong&gt;Limited perspective&lt;/strong&gt; —our personal 'touch' of the elephant—can prevent us from seeing the full scope of a network problem, especially in complex environments. &lt;strong&gt;Emotional investment&lt;/strong&gt; in our networks and our solutions can make it difficult to accept that a cherished methodology might be outdated or ineffective. Lastly, &lt;strong&gt;cognitive dissonance&lt;/strong&gt; arises when new information conflicts with our established beliefs, causing discomfort and, sometimes, denial.&lt;/p&gt;
&lt;p&gt;Recognizing these biases is the first step towards overcoming them. Like the blind men with the elephant, we must acknowledge that our perspective is just one part of a larger whole. We need to collaborate, share knowledge, and be open to the idea that our initial assessment may need adjustment.&lt;/p&gt;
&lt;h1&gt;Systematic Troubleshooting Steps&lt;/h1&gt;
&lt;p&gt;To ensure a comprehensive approach to network troubleshooting, following a structured methodology can help minimize the impact of personal bias:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Identify the Problem&lt;/strong&gt;: Clearly define the issue based on user reports and your own observations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Establish a Theory of Probable Cause&lt;/strong&gt;: Consider all potential causes based on the symptoms, not just those you have encountered before.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test the Theory&lt;/strong&gt;: This step verifies your hypothesis and ensures that the theory aligns with the reality of the problem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plan and Implement a Solution&lt;/strong&gt;: Develop a solution strategy that is both efficient and minimally disruptive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify System Functionality&lt;/strong&gt;: After applying the fix, confirm that the system operates as expected without introducing new issues.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Document&lt;/strong&gt;: Keep detailed records of the problem and solution for future reference and learning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback&lt;/strong&gt;: Communicate with all stakeholders to confirm the resolution and gather feedback for future improvements.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Divide and Conquer Technique&lt;/h1&gt;
&lt;p&gt;One effective strategy in troubleshooting is the "divide and conquer" technique. This approach involves breaking down a large problem into smaller, more manageable parts to isolate the source of the issue. By methodically eliminating segments of the network that are functioning properly, you can focus your efforts on the areas that are likely causing trouble. This technique not only simplifies complex problems but also helps in pinpointing exact issues, facilitating a quicker resolution.&lt;/p&gt;
&lt;p&gt;To further enhance the divide and conquer approach, the OSI Model or DoD Model can be invaluable tools. These models provide a layered framework that can help systematically isolate the problem area.  You can leverage these models to methodically check each layer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Physical Layer&lt;/strong&gt;: Verify all physical connections like cables and ports.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Link Layer&lt;/strong&gt;: Check MAC address filtering, Ethernet switches, and VLAN configurations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network Layer&lt;/strong&gt;: Ensure routing is intact and inspect IP configurations and subnet masks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transport Layer&lt;/strong&gt;: Look at TCP connections and port numbers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application Layer&lt;/strong&gt;: Check application-specific services that might impact connectivity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For instance, if in an optimal environment you were able to ping a device but now cannot, start at the network layer and work down.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Mastering network troubleshooting requires more than technical skills—it demands an open mind and an awareness of our own biases. Like the blind men and the elephant, we must remember that our perspective is limited and collaboration is key. By employing structured troubleshooting methods and techniques like divide and conquer, and utilizing models like OSI or DoD for layered analysis, we can overcome biases to maintain and restore our networks more effectively.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img alt="A humorous illustration of a caveman involved in network communications. The caveman, wearing traditional animal skin clothing, is standing in a primitive setting with a rocky background. He is swapping hardware components, holding a large, crude stone tablet etched with primitive symbols resembling a circuit board. Next to him, a wooden rack holds various stone and wooden devices shaped like modern routers and switches. The scene conveys a funny juxtaposition of ancient technology and modern networking concepts." src="images/caveman.jpg"&gt;&lt;/p&gt;</content><category term="Networking"/><category term="troubleshooting"/><category term="network"/><category term="bias"/><category term="OSI model"/><category term="divide and conquer"/></entry><entry><title>Objectifying Cisco Network Devices in Python with Netmiko</title><link href="/objectifying-cisco-network-devices-in-python-with-netmiko.html" rel="alternate"/><published>2024-12-09T00:00:00-08:00</published><updated>2024-12-09T00:00:00-08:00</updated><author><name>BlogByNuX</name></author><id>tag:None,2024-12-09:/objectifying-cisco-network-devices-in-python-with-netmiko.html</id><summary type="html">&lt;p&gt;Learn how to objectify Cisco network devices and their storage in Python using Netmiko for automation and scalability.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Managing network devices programmatically has become a crucial skill for network engineers. By objectifying network devices and their components, you can simplify operations, make your code modular, and automate tedious tasks. In this blog post, we’ll explore how to objectify a Cisco network device using Python and Netmiko, focusing on representing device storage with clear and reusable properties.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Why Objectify a Network Device?&lt;/h2&gt;
&lt;p&gt;Objectifying a network device means modeling it as a Python class that encapsulates all its properties and operations. This approach offers several benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Modularity&lt;/strong&gt;: Keep code organized and reusable.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Easily manage multiple devices.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;: Isolate and fix issues in one place.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;: Add features without breaking existing functionality.  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;The Plan&lt;/h2&gt;
&lt;p&gt;We’ll create two classes:  &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;CiscoDevice&lt;/code&gt;&lt;/strong&gt;: Represents a Cisco network device and its operations.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Storage&lt;/code&gt;&lt;/strong&gt;: Encapsulates storage-related properties, such as &lt;code&gt;bytes_free&lt;/code&gt; and &lt;code&gt;bytes_total&lt;/code&gt;.  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using &lt;strong&gt;Netmiko&lt;/strong&gt;, the &lt;code&gt;CiscoDevice&lt;/code&gt; class will connect to a Cisco device and fetch its storage information by parsing the output of the &lt;code&gt;dir bootflash:&lt;/code&gt; command.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Implementation&lt;/h2&gt;
&lt;h3&gt;Step 1: Define the &lt;code&gt;Storage&lt;/code&gt; Class&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;Storage&lt;/code&gt; class represents storage information on a network device, making it reusable and self-contained.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes_free&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes_total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes_free&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes_free&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes_total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes_total&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;Storage(bytes_free=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes_free&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, bytes_total=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes_total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Step 2: Define the &lt;code&gt;CiscoDevice&lt;/code&gt; Class&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;CiscoDevice&lt;/code&gt; class handles device connection and operations, including fetching storage details.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;netmiko&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ConnectHandler&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;CiscoDevice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;  &lt;span class="c1"&gt;# Will hold an instance of Storage&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Establish a Netmiko connection.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConnectHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;device_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cisco_ios&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Connected to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Failed to connect to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Close the Netmiko connection.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
            &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Disconnected from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;fetch_storage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Fetch storage details from the device.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Not connected to device&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;dir bootflash:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bytes free&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Parse the last line for storage details&lt;/span&gt;
                &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;bytes_free&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;(&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Extract free space&lt;/span&gt;
                &lt;span class="n"&gt;bytes_total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;            &lt;span class="c1"&gt;# Extract total space&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes_free&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bytes_free&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes_total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bytes_total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Storage fetched for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Failed to parse storage information&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Error fetching storage for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;CiscoDevice(name=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, ip=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, storage=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;h2&gt;Step 3: Putting It All Together&lt;/h2&gt;
&lt;p&gt;Here’s an example script that demonstrates connecting to a device and fetching its storage details.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Instantiate a CiscoDevice object&lt;/span&gt;
    &lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CiscoDevice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Router1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;192.168.1.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Connect to the device and fetch storage details&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_storage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Disconnect from the device&lt;/span&gt;
        &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Print the device details&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;h2&gt;Expected Output&lt;/h2&gt;
&lt;p&gt;Here’s what you might see when running the script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Connected to Router1 (192.168.1.1)
Storage fetched for Router1: &amp;lt;Storage(bytes_free=23456789, bytes_total=50000000)&amp;gt;
Disconnected from Router1 (192.168.1.1)
&amp;lt;CiscoDevice(name=Router1, ip=192.168.1.1, storage=&amp;lt;Storage(bytes_free=23456789, bytes_total=50000000)&amp;gt;)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;h2&gt;Key Benefits of This Approach&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Encapsulation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Storage&lt;/code&gt; class cleanly separates storage details from the main &lt;code&gt;CiscoDevice&lt;/code&gt; logic.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Easily extend the &lt;code&gt;CiscoDevice&lt;/code&gt; class to support additional features like fetching model, OS version, or other device-specific attributes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Handle connection and command execution errors gracefully, ensuring the script doesn't crash.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reusability&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Storage&lt;/code&gt; class can be reused in other contexts requiring storage information.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;By objectifying a Cisco network device and its storage, we’ve created a modular and reusable framework that simplifies device management. This approach not only saves time but also reduces errors and makes your code easier to maintain.&lt;/p&gt;
&lt;p&gt;Since we’ve now objectified the storage, we can easily run logic against it for advanced operations. For example, you could test if a new IOS file will fit on the device before attempting to upload it. This might look something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes_free&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;new_ios_file_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Sufficient storage space available. Proceeding with upload...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Insufficient storage space. Cleanup required before upload.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This capability allows for more intelligent automation, helping you handle edge cases and reduce manual interventions.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;What tasks would you like to automate next? Let us know in the comments or reach out on &lt;strong&gt;BlogByNuX&lt;/strong&gt;! If you’re interested in extending this script to fetch other device details, manage configurations, or implement dynamic decision-making, stay tuned for upcoming posts.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Happy automating!&lt;/em&gt; 🚀&lt;/p&gt;</content><category term="Networking"/><category term="Python"/><category term="Netmiko"/><category term="Automation"/><category term="Cisco"/></entry><entry><title>Welcome to BlogByNuX</title><link href="/welcome-to-blogbynux.html" rel="alternate"/><published>2024-12-07T00:00:00-08:00</published><updated>2024-12-07T00:00:00-08:00</updated><author><name>NuX</name></author><id>tag:None,2024-12-07:/welcome-to-blogbynux.html</id><summary type="html">&lt;p&gt;An introduction to BlogByNuX, a space where technology, cybersecurity, and life intersect, created to empower readers with practical skills and insights.&lt;/p&gt;</summary><content type="html">&lt;h1&gt;Welcome to BlogByNuX&lt;/h1&gt;
&lt;p&gt;Hello, and welcome to BlogByNuX!&lt;/p&gt;
&lt;p&gt;I’m a seasoned network engineer with over 20 years of experience in designing, securing, and optimizing complex systems. My passions for technology, cybersecurity, and sharing knowledge have led me to create this blog as a platform for learning, growth, and connection.&lt;/p&gt;
&lt;p&gt;Over the years, I’ve discovered a deep love for breaking down complex concepts into accessible insights. Whether guiding someone through troubleshooting a network issue or introducing new tools, I find joy in empowering others to tackle challenges with confidence. Teaching and mentoring have become integral to my journey, and BlogByNuX is a reflection of that passion.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;What BlogByNuX is About&lt;/h2&gt;
&lt;p&gt;This blog is a space where technology, security, and life intersect. My goal is for every reader to leave with practical skills, a deeper understanding, and the confidence to tackle challenges—not just in technology and cybersecurity, but also in life.&lt;/p&gt;
&lt;p&gt;Here’s what you can expect from BlogByNuX:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tech Tutorials&lt;/strong&gt;: Step-by-step guides to demystify technology.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Best Practices&lt;/strong&gt;: Insights and strategies to protect yourself and your systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lessons from Experience&lt;/strong&gt;: Stories and tips from my professional journey.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Life Insights&lt;/strong&gt;: Personal reflections on navigating life and mastering skills.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And because life is about balance, I’ll also share practical tips beyond the tech world, drawing on experiences like my journey as a certified NRA pistol instructor to offer advice on shooting techniques and firearm safety.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Who Is This Blog For?&lt;/h2&gt;
&lt;p&gt;BlogByNuX is for anyone eager to learn, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tech Enthusiasts&lt;/strong&gt;: People curious about the inner workings of technology.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cybersecurity Beginners&lt;/strong&gt;: Individuals taking their first steps in this exciting field.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seasoned Professionals&lt;/strong&gt;: Experts seeking fresh perspectives or exploring new tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lifelong Learners&lt;/strong&gt;: Readers looking for insights on topics ranging from mastering technology to improving life skills.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Why Pelican?&lt;/h2&gt;
&lt;p&gt;When choosing a platform for this blog, I went with Pelican, a lightweight and flexible static site generator built with Python. Python is a language I’m passionate about, and Pelican provides full control over my blog’s design and functionality without relying on complex backend systems.&lt;/p&gt;
&lt;p&gt;The process of setting up Pelican was both challenging and rewarding. Configuring it with Nginx in a reverse proxy environment tested my skills, but it also deepened my understanding of web server configurations. Customizing the themes to match my vision felt like crafting BlogByNuX from the ground up, and it was an experience I thoroughly enjoyed.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;What’s Next?&lt;/h2&gt;
&lt;p&gt;In the coming posts, I’ll cover topics that reflect the essence of BlogByNuX, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Practical Tech Tutorials&lt;/strong&gt;: Learn how to solve real-world problems step by step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cybersecurity Insights&lt;/strong&gt;: Discover best practices and tips to stay secure in today’s digital world.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Life Skills&lt;/strong&gt;: Gain new perspectives, whether it’s mastering technology or honing skills like firearm safety.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I don’t have a rigid posting schedule just yet, but my goal is to share meaningful, well-researched content whenever inspiration strikes. Every post will be crafted with the aim of adding value, whether you’re a beginner, an expert, or just curious to learn something new.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Thank you for stopping by, and I hope you’ll join me on this journey. If you have questions, feedback, or topics you’d like me to explore, don’t hesitate to reach out. Let’s learn, grow, and tackle challenges together—one post at a time.&lt;/p&gt;
&lt;p&gt;Welcome to BlogByNuX!&lt;/p&gt;</content><category term="Introduction"/><category term="technology"/><category term="cybersecurity"/><category term="life"/><category term="blog"/><category term="Pelican"/></entry></feed>