<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>jonmagic.com</title>
  <subtitle>Writing from Jonathan Hoyt on shipping software with AI agents, building teams, and the occasional shirt.</subtitle>
  <link href="https://jonmagic.com/feed.xml" rel="self"/>
  <link href="https://jonmagic.com"/>
  <updated>2026-06-04T00:00:00Z</updated>
  <id>https://jonmagic.com/</id>
  <author>
    <name>Jonathan Hoyt</name>
    <email>jonmagic@gmail.com</email>
  </author>
  
  <entry>
    <title>The Feedback Loop I Was Missing</title>
    <link href="https://jonmagic.com/posts/the-feedback-loop-i-was-missing/"/>
    <updated>2026-06-04T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/the-feedback-loop-i-was-missing/</id>
    <content type="html">&lt;p&gt;This last weekend I was doing my best to live in the moment and my daughter asked me if we could play Minecraft. We did for an hour or two and then, inspired by a conversation with a friend, I asked if she wanted to build her own Minecraft-like game.&lt;/p&gt;
&lt;p&gt;She was excited about the idea so I spent a few minutes with GitHub Copilot and put together an &lt;code&gt;AGENTS.md&lt;/code&gt; that had the rough draft of the milestones to build a game like, instructions to red-green-refactor, &lt;a href=&quot;https://thisistheway.to/ai&quot;&gt;my self-improvement loop&lt;/a&gt;, and an understanding that the agent would be driven by an eight-year-old.&lt;/p&gt;
&lt;p&gt;After setting up her computer with an agent and these instructions, things were going quite well but she kept asking me to explain what the agent was doing and every time it required input it would take her a while to turn her feedback into typed text that the agent could act on. &lt;em&gt;This constant struggle to understand the agent and respond resulted in lost attention and flow&lt;/em&gt;. So we started iterating.&lt;/p&gt;
&lt;h2 id=&quot;speaking-with-the-agent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/the-feedback-loop-i-was-missing/#speaking-with-the-agent&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Speaking with the agent&lt;/h2&gt;
&lt;p&gt;First we leveraged the &lt;a href=&quot;https://docs.github.com/en/copilot/how-tos/copilot-cli/use-copilot-cli/voice-input&quot;&gt;Voice mode&lt;/a&gt; built into agents like Copilot and Claude. This was a big win, she could press and hold the spacebar and dictate, read what was captured, and press enter to get the agent back to work. For an hour this was great, but she was getting frustrated waiting on me every time she needed the output explained.&lt;/p&gt;
&lt;p&gt;Then I had an idea to use the &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/SpeakText.html&quot;&gt;&lt;code&gt;say&lt;/code&gt; CLI&lt;/a&gt; that ships with macOS and a set of agent instructions to drive that CLI.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;&lt;code&gt;say &amp;quot;Hello, I am an agent and I am speaking to you.&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;So I updated the &lt;code&gt;AGENTS.md&lt;/code&gt; for the project to include the instructions below and &lt;strong&gt;it worked!&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p&gt;&lt;strong&gt;When using tools or doing multi-step work, speak short status updates with the macOS &lt;code&gt;say&lt;/code&gt; command. Do not read logs, code, secrets, or long explanations out loud.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;That said, what it read was still pretty technical, and this reminded me of something a coworker had mentioned they were using a lot in their prompts recently, &lt;a href=&quot;https://jonmagic.com/eli5/&quot;&gt;ELI5&lt;/a&gt;, aka explain it to me like I’m five years old. So I added this to the instructions.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p&gt;&lt;strong&gt;When you speak, speak like you are explaining to a five-year-old. Use simple language and short sentences.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;We got back to work and &lt;strong&gt;&lt;em&gt;the experience was incredible&lt;/em&gt;&lt;/strong&gt;. The agent would speak to us about what it was doing, what changed, and when it needed input. She could understand the updates without me having to explain them and she could stay in the flow by using voice input to respond to the agent’s requests.&lt;/p&gt;
&lt;h2 id=&quot;audio-triggers-different-brain-pathways&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/the-feedback-loop-i-was-missing/#audio-triggers-different-brain-pathways&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Audio triggers different brain pathways&lt;/h2&gt;
&lt;p&gt;After working like this for an hour &lt;strong&gt;&lt;em&gt;I realized my brain was responding to the audio updates in a different way than it did to text on a screen&lt;/em&gt;&lt;/strong&gt;. The audio updates made it easier for me to re-enter the agent’s state and understand what was happening without having to read through a wall of text.&lt;/p&gt;
&lt;p&gt;This is when the seed of an idea started to germinate 💡 Could a more natural feedback loop solve a problem I’d been struggling with for months? I often have multiple agents running but I can only focus on one project at a time. I was constantly hopping between agent windows to check on the status of each agent, which pulled me out of flow. &lt;em&gt;What if these simple spoken updates were queued so I could listen and react to them when I was ready?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/the-feedback-loop-i-was-missing/banner.webp&quot; alt=&quot;Tri-State Relay Service&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;say&lt;/code&gt; version proved the shape of the feedback loop, but it was too blunt for the way I actually work. If every agent can speak whenever it wants, the room gets noisy fast. I did not want a bunch of agents interrupting me and speaking over each other. &lt;strong&gt;I wanted each agent to leave a short update, and I wanted to decide when I was ready to hear it.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;turning-say-into-relay&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/the-feedback-loop-i-was-missing/#turning-say-into-relay&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Turning &lt;code&gt;say&lt;/code&gt; into Relay&lt;/h2&gt;
&lt;p&gt;That became &lt;a href=&quot;https://jonmagic.com/tsrs/&quot;&gt;Tri-State Relay Service&lt;/a&gt;, a small macOS app and CLI where agents leave short updates in a local queue instead of speaking over each other.&lt;/p&gt;
&lt;p&gt;Each project or context gets a line. A line can stay quiet while I am focused, wait with an update, and become active when I choose to listen.&lt;/p&gt;
&lt;p&gt;The goal is audio feedback on demand, not constant interruption.&lt;/p&gt;
&lt;p&gt;I’m releasing it for free and &lt;a href=&quot;https://github.com/jonmagic/tri-state-relay-service&quot;&gt;the source is on GitHub&lt;/a&gt;. I mostly want to get it into people’s hands and see whether this feedback loop helps anyone else.&lt;/p&gt;
&lt;p&gt;If you want to try it, &lt;a href=&quot;https://jonmagic.com/tsrs/&quot;&gt;here is the user manual and download&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>GitHub Copilot Session Search and Resume CLI</title>
    <link href="https://jonmagic.com/posts/github-copilot-session-search-and-resume-cli/"/>
    <updated>2026-04-12T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/github-copilot-session-search-and-resume-cli/</id>
    <content type="html">&lt;p&gt;Last week I switched to &lt;a href=&quot;https://docs.github.com/en/copilot/how-tos/copilot-cli&quot;&gt;copilot-cli&lt;/a&gt; as my full-time coding agent. I’d been splitting my time between it and &lt;a href=&quot;https://opencode.ai/&quot;&gt;opencode&lt;/a&gt; for months, using Copilot a few times a week, gravitating back to opencode for daily work. But after returning from two weeks of vacation to a fresh laptop, I committed to using only the latest copilot-cli for a full week. By the end of it I sent this to the team internally:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I gotta say, things are finally at the point where I’m not tempted to switch back to opencode. Amazing work everyone. I’m going to start annoying my friends that still use claude code and get them to try switching to copilot again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One friction point lingered though. Finding my way back to previous sessions.&lt;/p&gt;
&lt;h2 id=&quot;e-too-many-sessions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/github-copilot-session-search-and-resume-cli/#e-too-many-sessions&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; e-too-many-sessions&lt;/h2&gt;
&lt;p&gt;I run multiple Copilot sessions a day across different folders and repos. My &lt;a href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/&quot;&gt;Brain&lt;/a&gt; (personal knowledge base), work projects, side projects, home automation. Open a tab, start a session, do some work, close it, move on. An hour later I’d think “I need to pick that back up” and have no idea which session it was. My workaround was manually copy-pasting session IDs into my &lt;a href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/&quot;&gt;weekly note&lt;/a&gt; so I could &lt;code&gt;copilot --resume=&amp;lt;uuid&amp;gt;&lt;/code&gt; later. It worked, but it felt wrong.&lt;/p&gt;
&lt;h2 id=&quot;~%2F.copilot%2F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/github-copilot-session-search-and-resume-cli/#~%2F.copilot%2F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; ~/.copilot/ 👀&lt;/h2&gt;
&lt;p&gt;The copilot-cli stores all its state on disk at &lt;code&gt;~/.copilot/&lt;/code&gt;. Each session gets its own directory under &lt;code&gt;session-state/&lt;/code&gt; with an &lt;code&gt;events.jsonl&lt;/code&gt; event log and a &lt;code&gt;workspace.yaml&lt;/code&gt; metadata file. But the interesting discovery was &lt;code&gt;session-store.db&lt;/code&gt;, a SQLite database copilot-cli maintains automatically.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~/.copilot/
├── config.json
├── session-state/           # One directory per session
│   └── &amp;lt;uuid&amp;gt;/
│       ├── events.jsonl     # Every event that happened
│       ├── workspace.yaml   # Session metadata
│       └── checkpoints/     # Snapshot history
├── session-store.db         # ← The good stuff
└── mcp-config.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I opened &lt;code&gt;session-store.db&lt;/code&gt; with &lt;code&gt;sqlite3&lt;/code&gt; and found six tables.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;th&gt;What’s in it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sessions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ID, auto-generated summary, repository, branch, timestamps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;turns&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Every user message and assistant response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;checkpoints&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Titled snapshots with overviews and next steps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;session_files&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Every file touched during the session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;session_refs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Commits, PRs, and issues linked to the session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_index&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;FTS5 full-text search across all content&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That last one caught my eye. It looks like copilot-cli maintains an &lt;a href=&quot;https://www.sqlite.org/fts5.html&quot;&gt;FTS5 full-text search index&lt;/a&gt; across all session content. And the summaries in the &lt;code&gt;sessions&lt;/code&gt; table? Already generated automatically, no LLM call needed to get a human-readable title for every session.&lt;/p&gt;
&lt;h2 id=&quot;copilot-sessions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/github-copilot-session-search-and-resume-cli/#copilot-sessions&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; copilot-sessions&lt;/h2&gt;
&lt;p&gt;Once I understood the data, the tool was straightforward. Query the database, pipe through &lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;fzf&lt;/a&gt; for interactive fuzzy search, resume the chosen session:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Browse recent sessions&lt;/span&gt;
cs

&lt;span class=&quot;token comment&quot;&gt;# Search for a session&lt;/span&gt;
cs home assistant

&lt;span class=&quot;token comment&quot;&gt;# List without fzf&lt;/span&gt;
cs &lt;span class=&quot;token parameter variable&quot;&gt;-l&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  TIME     REPO             SESSION
  11m ago  brain            Home Assistant Automation Ideas
  1h ago   brain            Research Copilot CLI Theme
  4h ago   brain            Review And Seed Spotify Playlist
  13h ago  brain            Enable Ghostty SSH Terminal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pick one, hit Enter, and Copilot resumes right in your terminal. &lt;code&gt;ctrl-y&lt;/code&gt; copies the session ID to clipboard if you need it elsewhere.&lt;/p&gt;
&lt;p&gt;Search uses fzf’s fuzzy matching against session summaries, all user messages, and repository names. That means it’s typo-tolerant. &lt;code&gt;mincraft&lt;/code&gt; finds your Minecraft session, &lt;code&gt;sptoify&lt;/code&gt; finds Spotify. It supports substring matching and multi-word queries too. The user messages are appended off-screen so fzf can match against them without cluttering the display.&lt;/p&gt;
&lt;p&gt;All the formatting (relative timestamps, repo name truncation, column layout) happens inside a single SQLite query. No bash loops or per-row shell-outs. Startup is about 20ms for hundreds of sessions.&lt;/p&gt;
&lt;p&gt;I published it as &lt;a href=&quot;https://github.com/jonmagic/copilot-sessions&quot;&gt;copilot-sessions&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p&gt;If you use &lt;code&gt;copilot -p &amp;lt;prompt&amp;gt;&lt;/code&gt; for automations (e.g., a cronjob running every few minutes), those sessions will show up in your search results too. I found it helpful to have the automation’s prompt include a step that deletes its own session from &lt;code&gt;session-store.db&lt;/code&gt; at the end so it doesn’t clutter things up or become resumable.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;%E2%80%A6one-more-thing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/github-copilot-session-search-and-resume-cli/#%E2%80%A6one-more-thing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; …one more thing&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;events.jsonl&lt;/code&gt; file in each session directory is a streaming log of everything that happened. Every tool call, every file edit, every shell command, all with timestamps:&lt;/p&gt;
&lt;pre class=&quot;language-jsonl&quot;&gt;&lt;code class=&quot;language-jsonl&quot;&gt;{&quot;type&quot;:&quot;session.start&quot;,&quot;timestamp&quot;:&quot;...&quot;,&quot;data&quot;:{&quot;context&quot;:{&quot;repository&quot;:&quot;jonmagic/copilot-sessions&quot;,&quot;branch&quot;:&quot;main&quot;}}}
{&quot;type&quot;:&quot;tool.execution_start&quot;,&quot;timestamp&quot;:&quot;...&quot;,&quot;data&quot;:{&quot;toolName&quot;:&quot;grep&quot;,&quot;arguments&quot;:{...}}}
{&quot;type&quot;:&quot;tool.execution_complete&quot;,&quot;timestamp&quot;:&quot;...&quot;,&quot;data&quot;:{&quot;success&quot;:true}}
{&quot;type&quot;:&quot;session.shutdown&quot;,&quot;timestamp&quot;:&quot;...&quot;,&quot;data&quot;:{&quot;modelMetrics&quot;:{&quot;gpt-5.4&quot;:{&quot;usage&quot;:{&quot;inputTokens&quot;:192048}}}}}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s a lot you could build on this. Session analytics, cross-session file search, timeline visualizations. For now I’m happy just being able to find my sessions without keeping a manual list.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;I work at GitHub, which helped me confirm some of these findings by reviewing internal code. But everything described here is observable by anyone with copilot-cli installed. Just open &lt;code&gt;~/.copilot/&lt;/code&gt; and start exploring.&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <title>Stop Putting Secrets in .env Files</title>
    <link href="https://jonmagic.com/posts/stop-putting-secrets-in-dotenv-files/"/>
    <updated>2026-02-27T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/stop-putting-secrets-in-dotenv-files/</id>
    <content type="html">&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;&lt;strong&gt;Update (Feb 28, 2026):&lt;/strong&gt; This post got a lot of discussion on &lt;a href=&quot;https://news.ycombinator.com/item?id=47188465&quot;&gt;Hacker News&lt;/a&gt; and &lt;a href=&quot;https://lobste.rs/s/eai9st/stop_putting_secrets_env_files&quot;&gt;Lobsters&lt;/a&gt;. Two things worth addressing.&lt;/p&gt;
&lt;p&gt;First, several people pointed out &lt;a href=&quot;https://developer.1password.com/docs/environments/local-env-file&quot;&gt;1Password Environments&lt;/a&gt;, a newer feature I hadn’t tried yet. It mounts a &lt;code&gt;.env&lt;/code&gt; file backed by a UNIX named pipe (FIFO) so your existing dotenv libraries just work, but no plaintext ever lands on disk. Authorization persists until 1Password locks, which solves the repeated Touch ID prompts you’d get with &lt;code&gt;op run&lt;/code&gt;. If you’re already using 1Password this is probably the best option available today.&lt;/p&gt;
&lt;p&gt;Second, a fair critique. Injecting secrets as environment variables doesn’t make them invisible. On Linux, any process running as your user can read &lt;code&gt;/proc/self/environ&lt;/code&gt; (or &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/environ&lt;/code&gt; for other processes you own). On macOS there’s no &lt;code&gt;/proc&lt;/code&gt; filesystem, but environment variables are still accessible through other means. Runtime injection is a meaningful improvement over plaintext files sitting on disk, but it’s not a complete security boundary. For higher-stakes environments, look at tools that use short-lived credentials, mounted secrets via tmpfs, or hardware-backed keystores.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;A few weeks ago my friend Harrison (&lt;a href=&quot;https://github.com/hktouw&quot;&gt;@hktouw&lt;/a&gt;) and I did our yearly Tesla FSD cruise around the Bay Area — seven hours of letting the car drive while we talk about whatever comes to mind. This was the first year we never had to take over the wheel, which meant even more time for conversation. We covered AI adoption, investing, and then landed on something that’s been bugging me for a while. Why do we still store credentials in plaintext &lt;code&gt;.env&lt;/code&gt; files?&lt;/p&gt;
&lt;p&gt;I’d been using 1Password to store individual secrets for a while, pulling them one at a time with the CLI. Harrison took it a step further. “Why not store the whole &lt;code&gt;.env&lt;/code&gt; file’s worth of secrets as fields in a single 1Password item?” he said. Simple. Obvious in hindsight. And it led me down a rabbit hole of rethinking how I handle secrets in every project.&lt;/p&gt;
&lt;p&gt;The result is a pattern I’ve been using for the past month that I want to share. It’s not complicated. It doesn’t require enterprise tooling. It works today with tools you probably already have.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://jonmagic.com/images/posts/stop-putting-secrets-in-dotenv-files/secure-env-demo.mp4&quot; controls=&quot;&quot; width=&quot;100%&quot;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-problem-with-.env-files&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/stop-putting-secrets-in-dotenv-files/#the-problem-with-.env-files&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The problem with .env files&lt;/h2&gt;
&lt;p&gt;We all know &lt;code&gt;.env&lt;/code&gt; files are supposed to be gitignored. And they usually are. But beyond the git risk, having credentials stored in plaintext just feels bad. If you leave your laptop unlocked at a coffee shop or someone gets access to your machine, those &lt;code&gt;.env&lt;/code&gt; files are sitting right there — high-value targets with zero protection.&lt;/p&gt;
&lt;p&gt;Here’s what actually happens with &lt;code&gt;.env&lt;/code&gt; files.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They get copied into Slack DMs when onboarding a new teammate&lt;/li&gt;
&lt;li&gt;They accumulate across 20+ projects with the same stale API key&lt;/li&gt;
&lt;li&gt;A credential gets rotated and you’re hunting through every project directory to find the copies&lt;/li&gt;
&lt;li&gt;Someone clones the repo on a new machine and asks you to send them the &lt;code&gt;.env&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;They sit on disk as plaintext, readable by any process running as your user&lt;/li&gt;
&lt;li&gt;If someone gains access to your machine, they instantly have every credential you’ve ever stored this way&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The twelve-factor app told us to put config in the environment. Good advice. But &lt;code&gt;.env&lt;/code&gt; files are a leaky implementation of that principle. They’re plaintext files pretending to be environment variables.&lt;/p&gt;
&lt;h2 id=&quot;inject-at-runtime%2C-never-store-on-disk&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/stop-putting-secrets-in-dotenv-files/#inject-at-runtime%2C-never-store-on-disk&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Inject at runtime, never store on disk&lt;/h2&gt;
&lt;p&gt;The pattern is simple. Instead of loading secrets from a file, you use a wrapper script that fetches secrets from a secure store and injects them as environment variables into your process:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Instead of this:&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;source&lt;/span&gt; .env &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; server.js

&lt;span class=&quot;token comment&quot;&gt;# Do this:&lt;/span&gt;
./with-1password.sh &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; server.js
&lt;span class=&quot;token comment&quot;&gt;# or&lt;/span&gt;
./with-keychain.sh &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; server.js&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your application doesn’t change at all. It still reads &lt;code&gt;process.env.API_KEY&lt;/code&gt; or &lt;code&gt;$DATABASE_URL&lt;/code&gt; the same way it always did. The difference is where the values come from.&lt;/p&gt;
&lt;p&gt;I built a &lt;a href=&quot;https://github.com/jonmagic/secure-env-demo&quot;&gt;demo repo&lt;/a&gt; with two working implementations: one for 1Password CLI and one for macOS Keychain. You can clone it and try both in about five minutes.&lt;/p&gt;
&lt;h2 id=&quot;1password-cli&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/stop-putting-secrets-in-dotenv-files/#1password-cli&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; 1Password CLI&lt;/h2&gt;
&lt;p&gt;This is the approach Harrison and I were originally talking about, and it’s the one I reach for most. If you already use 1Password, the CLI (&lt;code&gt;op&lt;/code&gt;) makes this almost frictionless.&lt;/p&gt;
&lt;p&gt;The key insight is that 1Password supports &lt;strong&gt;secret references&lt;/strong&gt; — URIs like &lt;code&gt;op://Development/myapp/api-key&lt;/code&gt; that point to a field in your vault. You can put these references in a file that’s safe to commit:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .env.1password — safe to commit, contains no secrets&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;API_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;op://Development/secure-env-demo/api-key
&lt;span class=&quot;token assign-left variable&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;op://Development/secure-env-demo/database-url
&lt;span class=&quot;token assign-left variable&quot;&gt;WEBHOOK_SECRET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;op://Development/secure-env-demo/webhook-secret&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the wrapper script is almost trivially simple:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;op&lt;/span&gt; run --env-file&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.env.1password&quot;&lt;/span&gt; -- &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$@&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it. &lt;code&gt;op run&lt;/code&gt; reads the references, fetches each secret from your vault (authenticating via Touch ID or your master password), injects them as environment variables, and runs your command. Secrets never touch disk as plaintext. As a bonus, &lt;code&gt;op run&lt;/code&gt; automatically masks secret values if they accidentally appear in stdout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setup is a one-time thing.&lt;/strong&gt; You create a vault item with your secrets (the demo repo includes a setup script for this), customize the references in &lt;code&gt;.env.1password&lt;/code&gt;, and you’re done. Every developer on the team can share the same &lt;code&gt;.env.1password&lt;/code&gt; file in version control and resolve it against their own 1Password account.&lt;/p&gt;
&lt;h2 id=&quot;or-macos-keychain&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/stop-putting-secrets-in-dotenv-files/#or-macos-keychain&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Or macOS Keychain&lt;/h2&gt;
&lt;p&gt;Not everyone uses 1Password, and that’s fine. If you’re on a Mac, you already have a secrets manager built into the OS. The &lt;code&gt;security&lt;/code&gt; command can read and write to your login keychain, and macOS gates access with your password or Touch ID.&lt;/p&gt;
&lt;p&gt;The wrapper script reads each secret from Keychain and exports it.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;declare&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-A&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;SECRETS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;API_KEY&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;secure-env-demo/api-key&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;DATABASE_URL&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;secure-env-demo/database-url&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;WEBHOOK_SECRET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;secure-env-demo/webhook-secret&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;SECRETS&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;@&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;}&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${SECRETS&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;$var&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;}&lt;/span&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;security find-generic-password &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$USER&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$service&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-w&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$var&lt;/span&gt;=&lt;span class=&quot;token variable&quot;&gt;$value&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$@&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Storing a secret is one command.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;security add-generic-password &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$USER&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;secure-env-demo/api-key&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sk-your-key&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-U&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s a bit more manual than the 1Password approach — you maintain the mapping in the script rather than a reference file — but it works without any third-party dependencies.&lt;/p&gt;
&lt;h2 id=&quot;what-you-gain&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/stop-putting-secrets-in-dotenv-files/#what-you-gain&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What you gain&lt;/h2&gt;
&lt;p&gt;The immediate benefit is obvious — no more plaintext secrets on disk. But there are a few less obvious wins.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One source of truth.&lt;/strong&gt; When a credential rotates, you update it in one place. Every project that references it picks up the change automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Onboarding gets simpler.&lt;/strong&gt; Instead of “here’s the &lt;code&gt;.env&lt;/code&gt; file, don’t lose it,” you say “set up 1Password and run the setup script.” The secrets are in the vault with proper access controls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Auditing.&lt;/strong&gt; 1Password and Keychain both maintain access logs. You can see who accessed which secrets and when. A &lt;code&gt;.env&lt;/code&gt; file gives you none of that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It works with anything.&lt;/strong&gt; The wrapper pattern is language and framework agnostic. &lt;code&gt;./with-1password.sh docker compose up&lt;/code&gt; works just as well as &lt;code&gt;./with-1password.sh pytest&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-about-other-tools%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/stop-putting-secrets-in-dotenv-files/#what-about-other-tools%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What about other tools?&lt;/h2&gt;
&lt;p&gt;There’s a whole ecosystem of secrets management tools — &lt;a href=&quot;https://doppler.com/&quot;&gt;Doppler&lt;/a&gt;, &lt;a href=&quot;https://infisical.com/&quot;&gt;Infisical&lt;/a&gt;, &lt;a href=&quot;https://www.vaultproject.io/&quot;&gt;HashiCorp Vault&lt;/a&gt;, &lt;a href=&quot;https://github.com/getsops/sops&quot;&gt;SOPS&lt;/a&gt;, &lt;a href=&quot;https://dotenvx.com/&quot;&gt;dotenvx&lt;/a&gt;. They’re all good, and if you’re running a team of 50+ engineers you should probably be evaluating them.&lt;/p&gt;
&lt;p&gt;But for most developers working on personal projects or small teams, the 1Password or Keychain approach hits a sweet spot: minimal setup, no infrastructure to manage, and you’re probably already paying for the tools.&lt;/p&gt;
&lt;p&gt;The important thing isn’t which tool you pick. It’s the pattern. &lt;strong&gt;Store secrets in a vault, inject at runtime, never write plaintext to disk.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;try-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/stop-putting-secrets-in-dotenv-files/#try-it&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Try it&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/jonmagic/secure-env-demo&quot;&gt;secure-env-demo&lt;/a&gt; repo has everything you need to try both approaches. Clone it, pick the one that fits your setup, and run the demo app:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/jonmagic/secure-env-demo.git
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; secure-env-demo

&lt;span class=&quot;token comment&quot;&gt;# 1Password path:&lt;/span&gt;
./setup-1password.sh
./with-1password.sh ./app.sh

&lt;span class=&quot;token comment&quot;&gt;# Keychain path:&lt;/span&gt;
./setup-keychain.sh
./with-keychain.sh ./app.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s a small change to how you work, but once you do it you won’t go back. Every time I see a &lt;code&gt;.env&lt;/code&gt; file now I think about that conversation in the Tesla and wonder why I didn’t do this years ago.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>A Practical Guide to Writing with AI</title>
    <link href="https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/"/>
    <updated>2026-02-13T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/</id>
    <content type="html">&lt;p&gt;I use AI in my writing all the time. For research, for turning messy transcripts into coherent sentences, for drafting, for getting feedback. But the way I use it matters. This isn’t about handing the wheel to an AI and publishing whatever it spits out. It’s a collaboration, a conversation, where the AI assists me and I stay in the driver’s seat.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/a-practical-guide-to-writing-with-ai/writing-in-notebook-and-agent-prompt-in-background.webp&quot; alt=&quot;Writing in a notebook with an agent prompt in the background&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I’ve been refining this process over the past year and sharing bits of it in PR reviews, Slack threads, and conversations with colleagues. Here’s the full picture.&lt;/p&gt;
&lt;h2 id=&quot;why-bother-with-a-process%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/#why-bother-with-a-process%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Why bother with a process?&lt;/h2&gt;
&lt;p&gt;There’s a real tension around AI-written content right now. A colleague put it well: “Why should I bother to read something someone else couldn’t be bothered to read?” And she’s right. If you feed a prompt into an AI and publish the output without reading it yourself, people can tell. The writing feels strenuous to parse, slightly off, like a conversation with someone who knows all the words but none of the stories.&lt;/p&gt;
&lt;p&gt;I’ve gotten feedback on my own writing from people who know I use AI heavily. The honest ones say they can sometimes tell. But the feedback I hear most is that my writing feels like me, and I think that’s because of how I use AI, not whether I use it.&lt;/p&gt;
&lt;p&gt;The goal is writing that a reader experiences as human, thoughtful, and worth their time, even though AI was deeply involved in creating it.&lt;/p&gt;
&lt;h2 id=&quot;step-1%3A-collect-all-your-context-in-one-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/#step-1%3A-collect-all-your-context-in-one-place&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Step 1: Collect all your context in one place&lt;/h2&gt;
&lt;p&gt;Before I write anything, I gather everything related to the topic. This sounds obvious but it’s the step most people skip, and it’s the one that makes everything else work.&lt;/p&gt;
&lt;p&gt;What I collect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transcripts from every conversation I had while working on the thing&lt;/li&gt;
&lt;li&gt;Research I did along the way&lt;/li&gt;
&lt;li&gt;Slack conversations&lt;/li&gt;
&lt;li&gt;Links to all related issues and PRs&lt;/li&gt;
&lt;li&gt;Screenshots and diagrams&lt;/li&gt;
&lt;li&gt;Transcripts from &lt;a href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#the-minimal-reproducible-stack&quot;&gt;walk and talks&lt;/a&gt; where a lot of my initial ideation and final prose takes shape&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This sounds like a lot of work, and it can be at first if you haven’t developed a habit around collecting these things as you go. All of my workflows center around collecting artifacts in my Brain folder (a personal knowledge base), so by the time I sit down to write it’s as simple as “please collect all my context on topic X” and the agent does the work for me.&lt;/p&gt;
&lt;p&gt;In my experience the quality of AI-assisted writing is directly proportional to the quality of context you give the AI. Garbage in, garbage out. Rich context in, rich writing out.&lt;/p&gt;
&lt;h2 id=&quot;step-2%3A-organize-and-find-your-story-arc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/#step-2%3A-organize-and-find-your-story-arc&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Step 2: Organize and find your story arc&lt;/h2&gt;
&lt;p&gt;Give all the context to an agent and ask it to help you organize it. Then ask for a few pitches with story arcs.&lt;/p&gt;
&lt;p&gt;For agents, I use whatever fits the moment. Right now my go-to is an agent called OpenCode, but I also use Copilot CLI, and Copilot in VS Code. The tool doesn’t matter much. What matters is giving it the full picture and asking it to help you see the shape of the story.&lt;/p&gt;
&lt;p&gt;Here’s something I’ve learned the hard way: AI-generated story arcs can feel samey. People who read a lot of AI-assisted writing start to recognize the patterns — the “journey from X to Y” structure, the tidy three-act narratives. The arcs aren’t bad, but they’re recognizable, and recognizable is the opposite of what you want.&lt;/p&gt;
&lt;p&gt;So I’ve been leaning more into interview mode. Instead of asking the agent for story arc pitches and picking one, I ask it to interview me about the topic. Agents are surprisingly good at interviewing and it often gets me to think about things I hadn’t considered. Questions like “what surprised you most about this work?” or “who was the audience you kept thinking about?” pull out the narrative I was carrying in my head but hadn’t articulated. The arc that emerges from an interview is yours — it has your emphasis, your surprises, your priorities — and that’s much harder for a reader to clock as AI-shaped.&lt;/p&gt;
&lt;p&gt;You can still ask for pitches if you want a starting point. Just be aware that the more the structure comes from the AI, the more it’ll read like AI. If none of the arcs feel right, give it that feedback. Ask for more ideas, or give it some of your own. But when I want the piece to really feel like mine, I start with the interview.&lt;/p&gt;
&lt;h2 id=&quot;step-3%3A-get-the-rough-draft&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/#step-3%3A-get-the-rough-draft&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Step 3: Get the rough draft&lt;/h2&gt;
&lt;p&gt;Once you have a story arc figured out you can either write it by hand or ask the agent for a rough draft. I usually ask for a rough draft, including placeholders for diagrams or pictures.&lt;/p&gt;
&lt;p&gt;I get pretty good results from rough drafts, but that didn’t happen by accident. Over time I’ve built up a “voice and tone” profile that includes examples of my writing along with the principles I apply when I write. The examples come from things I’ve published on my blog and elsewhere. This gives the AI a concrete target to aim for rather than its default style.&lt;/p&gt;
&lt;p&gt;If you don’t have a voice profile yet, you can start by giving the agent three or four pieces of your own writing and saying “match this tone.” It’s not as refined as a full voice guide but it gets you most of the way there.&lt;/p&gt;
&lt;h2 id=&quot;step-4%3A-the-editing-conversation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/#step-4%3A-the-editing-conversation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Step 4: The editing conversation&lt;/h2&gt;
&lt;p&gt;This is where the real work happens, and it’s what separates writing that feels human from writing that feels like AI slop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If the agent wrote the draft:&lt;/strong&gt; Go sentence by sentence and create a list of feedback. You can just edit things yourself manually, but if it’s going to need major rework it’s often better to give the AI all that extra context. Make this a conversation or an interview.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you wrote it yourself:&lt;/strong&gt; Ask the agent to give you feedback. It’ll catch repetition, unclear transitions, and structural issues you’re too close to see.&lt;/p&gt;
&lt;p&gt;Things I watch for in AI-generated prose, from specific feedback I’ve given on real PR reviews:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Repetition of themes.&lt;/strong&gt; AI loves to hammer a point home across multiple sections. In a recent review I flagged that the same arc (“this went from painful to boring”) appeared in three separate sections. Once is powerful. Three times is a newsletter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The colon tell.&lt;/strong&gt; Phrases like “If you’ve ever been near infrastructure, you know: DDoS isn’t theoretical” are an AI fingerprint. Turn colons into commas, or better yet rewrite those portions. A caveat: some people naturally write with colons, so this is only a tell if it’s not already part of your style. These stylistic fingerprints cut both ways. AI introduced me to em dashes and now I genuinely love using them, so I give myself a pass. A colleague who always used em dashes told me she’s been trying to break the habit now that AI overuses them. The point isn’t to avoid specific punctuation — it’s to know your own patterns well enough to tell the difference between your voice and the AI’s.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headers that try too hard.&lt;/strong&gt; Story-arc headers like “The Turning Point” or “Why Everything Changed” can feel less human. Simple, direct headers work better.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read it out loud.&lt;/strong&gt; If a section doesn’t sound like something you’d actually say, make small tweaks until it feels like you. This is the single most effective editing technique I’ve found.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-5%3A-the-voice-memo-trick&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/#step-5%3A-the-voice-memo-trick&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Step 5: The voice memo trick&lt;/h2&gt;
&lt;p&gt;For writing that really needs to sound like you, I use a technique that’s become central to my process.&lt;/p&gt;
&lt;p&gt;I use the Voice Memos app on my phone to record myself talking through the story at a high level, just the natural flow of how I’d explain it to someone. Then I take the transcription and use it as a base to write from. This gets my natural storytelling rhythm into the writing in a way that typing from scratch often doesn’t.&lt;/p&gt;
&lt;p&gt;Then I lean heavily on AI for research, writing and rewriting small sections. When I hit the detailed parts of the story, I do more voice recordings to capture the nuance, then use those transcripts to refine the writing.&lt;/p&gt;
&lt;p&gt;The result is prose that has my actual cadence and phrasing baked in at the structural level, with AI handling the polish and filling in details I’d otherwise spend hours looking up.&lt;/p&gt;
&lt;h2 id=&quot;step-6%3A-human-review&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/#step-6%3A-human-review&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Step 6: Human review&lt;/h2&gt;
&lt;p&gt;Give it to another human now that you’ve checked all your work and the agent’s work. Get their feedback. This step is non-negotiable. AI can’t tell you if your writing resonates with a real person. Only a real person can do that.&lt;/p&gt;
&lt;h2 id=&quot;step-7%3A-publish&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/#step-7%3A-publish&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Step 7: Publish&lt;/h2&gt;
&lt;p&gt;Mash that publish button.&lt;/p&gt;
&lt;h2 id=&quot;the-underlying-philosophy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-practical-guide-to-writing-with-ai/#the-underlying-philosophy&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The underlying philosophy&lt;/h2&gt;
&lt;p&gt;I use AI more for research and outlining than for final content. The finished piece has large portions written by me. I sometimes joke that AI was designed to just sound like me, but the truth is I’ve put deliberate work into making the collaboration seamless.&lt;/p&gt;
&lt;p&gt;The people who are frustrated with AI writing, and they have every reason to be, are reacting to writers who aren’t doing the work. They’re not reading their own output. They’re not editing. They’re not bringing their own voice to the table. And readers can feel it.&lt;/p&gt;
&lt;p&gt;Writing with AI is a collaboration. The AI brings speed, research capability, and tireless willingness to try different framings. You bring the stories, the judgment, and the voice. Neither one works well without the other.&lt;/p&gt;
&lt;p&gt;The skill that matters isn’t “prompting” or “using AI.” It’s learning how to have a productive conversation with a collaborator who has perfect recall and no taste. That’s a skill worth developing.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Securing My Home Network with AI</title>
    <link href="https://jonmagic.com/posts/securing-my-home-network-with-ai/"/>
    <updated>2026-02-08T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/securing-my-home-network-with-ai/</id>
    <content type="html">&lt;p&gt;I spent the weekend making my home network more secure, and the whole thing was just a conversation.&lt;/p&gt;
&lt;p&gt;Not “I asked an AI to generate a security checklist and then went through it.” More like: I sat down with a CLI agent, started talking about my network, and kept going. Over the next several hours, we port-scanned the network, audited what was exposed, hardened the NAS, built documentation crawlers, wrote an 8-phase improvement plan, and generated 24 Markdown docs from the Synology API. I never opened a browser to search for how to do any of it. I just kept talking.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/securing-my-home-network-with-ai/jonmagic-at-desk-vibing-v3.webp&quot; alt=&quot;A weekend nmap session&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I’ve been thinking a lot about &lt;a href=&quot;https://jonmagic.com/posts/designing-collaborations-not-just-automations/&quot;&gt;designing collaborations rather than just automations&lt;/a&gt;, and this project turned out to be the most fun example yet. The AI did the coding. I made the decisions. And the project harness we built along the way kept getting smarter.&lt;/p&gt;
&lt;h2 id=&quot;the-setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/securing-my-home-network-with-ai/#the-setup&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Setup&lt;/h2&gt;
&lt;p&gt;My home network is the usual story of accumulated decisions. Fiber into a gateway in IP passthrough mode, feeding a mesh router, serving about 46 devices on a flat network. A Synology NAS running Docker containers for game servers, an nginx reverse proxy, Let’s Encrypt cert management, and a few other things.&lt;/p&gt;
&lt;p&gt;One of the first things the agent generated was a topology diagram. Here’s a simplified version with fake addresses:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Internet
  │
  ▼
┌──────────────┐
│   Gateway    │  passthrough mode
│  (fiber ISP) │
└──────┬───────┘
       │
┌──────┴───────┐
│  Mesh Router │
│  + 2 sats    │
└──────┬───────┘
       │
       ├── NAS
       │    ├── Docker: nginx reverse proxy (TLS)
       │    ├── Docker: game servers
       │    ├── Docker: certbot (Let&#39;s Encrypt)
       │    └── Tailscale VPN
       │
       ├── Laptops, phones, tablets
       ├── Smart TV, streaming devices
       ├── IoT: smart plugs, cameras, sensors
       └── ... ~40 more devices
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having this in a version-controlled Markdown file—generated from the conversation—turned out to be surprisingly useful. It became the reference point for every decision that followed.&lt;/p&gt;
&lt;p&gt;I’d been meaning to audit the whole setup for a while. Not because anything was broken—everything worked fine—but because I’d been port-forwarding and enabling services for years without ever going back to see what the cumulative result looked like. It was a weekend project I kept not starting.&lt;/p&gt;
&lt;p&gt;What made it fun this time was the format. Instead of researching and executing solo, I opened &lt;a href=&quot;https://opencode.ai/&quot;&gt;OpenCode&lt;/a&gt;—a CLI coding agent—and just started a conversation.&lt;/p&gt;
&lt;h2 id=&quot;just-keep-talking&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/securing-my-home-network-with-ai/#just-keep-talking&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Just Keep Talking&lt;/h2&gt;
&lt;p&gt;The first thing I said was something like “help me understand what’s exposed on my network.” The agent ran &lt;code&gt;nmap&lt;/code&gt;, parsed the results, and we talked through each open port together. Some were intentional (the game server, the reverse proxy). Some were not—services I’d never intentionally exposed to the internet. We built a security audit document right there in the conversation, categorizing everything by severity.&lt;/p&gt;
&lt;p&gt;Here’s roughly what that audit looked like (with fake details):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;External Port Scan Results
──────────────────────────
PORT      SERVICE                 STATUS
xx/tcp    reverse proxy (HTTP)    ✓ Intentional
xx/tcp    reverse proxy (TLS)     ✓ Intentional
xx/tcp    game server             ✓ Intentional
xx/tcp    storage replication     ✗ NOT INTENTIONAL
xx/tcp    admin UI                ✗ NOT INTENTIONAL
xx/tcp    discovery service       ✗ NOT INTENTIONAL

Risk: 3 services exposed that should only be reachable on LAN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Seeing it laid out like that made the problem concrete. Three ports I’d never meant to expose, sitting there for who knows how long.&lt;/p&gt;
&lt;p&gt;What surprised me was how much I was learning just by talking it through. I work on GitHub’s Safety &amp;amp; Integrity team building infrastructure for abuse prevention at scale, but at home I didn’t have runbooks or institutional knowledge. The conversation replaced all of that. I’d ask “what does this service do and why would it be exposed?” and the agent would explain, and then I’d decide what to do about it. It felt like pair programming with someone who happens to know every Synology forum post ever written.&lt;/p&gt;
&lt;p&gt;From that first scan, the conversation just kept going. We narrowed the port forwarding rules on the router. We disabled remote management on the Orbi. We started on the NAS. Each thing led naturally to the next thing, and I never had to context-switch to a browser or a different tool.&lt;/p&gt;
&lt;h2 id=&quot;the-project-harness&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/securing-my-home-network-with-ai/#the-project-harness&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Project Harness&lt;/h2&gt;
&lt;p&gt;A few sessions in, I realized this was becoming a real project. So I did what I’d do at work—I gave it structure.&lt;/p&gt;
&lt;p&gt;I set up a repo with three kinds of content: &lt;strong&gt;reference docs&lt;/strong&gt; generated by crawlers and API scripts (snapshots of every device’s current configuration), &lt;strong&gt;plans&lt;/strong&gt; for multi-step work like NAS hardening, and &lt;strong&gt;&lt;a href=&quot;https://agentconfig.org/skills/&quot;&gt;agent skills&lt;/a&gt;&lt;/strong&gt; that teach the agent how to operate specific parts of the network.&lt;/p&gt;
&lt;p&gt;The skills are the fun part. Each one is a Markdown file that gives the agent context about a specific piece of the network. How to SSH into the NAS, which auth method to use. Where Docker containers live on disk. What the network topology looks like. When the agent loads a skill, it has the context to actually do things safely instead of guessing.&lt;/p&gt;
&lt;p&gt;Here’s what made this feel different from other AI projects I’ve done: the skills grew out of the conversation itself. Every time the agent needed information it didn’t have—or made a wrong assumption—we’d write that knowledge into a skill file. This is the &lt;a href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/&quot;&gt;improvement loop&lt;/a&gt; pattern applied to infrastructure instead of code.&lt;/p&gt;
&lt;p&gt;Some of the skills we ended up with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;nas-manage&lt;/strong&gt;: Connection details, storage layout, Docker container inventory, and a note that the root filesystem sitting at 90% is normal (so the agent doesn’t flag it as a problem every time).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;network-monitor&lt;/strong&gt;: Ping sweeps, port checks, service availability commands.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;network-config&lt;/strong&gt;: How to query the router and gateway using their crawled documentation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;crawl-device&lt;/strong&gt;: How to re-crawl each device’s UI to regenerate docs after making changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;improvement-loop&lt;/strong&gt;: The systematic process for turning agent mistakes into permanent fixes.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Skills vs. docs — a work in progress.&lt;/strong&gt; The line between “this is a skill” and “this is a doc” is still blurry. Skills are addressed to the agent: “when asked to do X, here’s how.” Docs are records of state: “here’s what the network looks like right now.” But in practice, skills embed reference data (IPs, device tables) so the agent can act without extra lookups, which means that data lives in two places. And some docs contain step-by-step instructions that read like skills. The pragmatic rule we landed on: if the agent needs it to &lt;em&gt;do something&lt;/em&gt;, it’s a skill; if it exists as a &lt;em&gt;record&lt;/em&gt;, it’s a doc. But I’d like to tighten this up — probably by having skills link to docs for reference data instead of duplicating it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;By the later sessions, the agent could SSH into the NAS, check a configuration, and update the documentation without me explaining anything. The harness had absorbed enough context to be genuinely useful.&lt;/p&gt;
&lt;h2 id=&quot;nas-hardening%3A-the-fun-bits&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/securing-my-home-network-with-ai/#nas-hardening%3A-the-fun-bits&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; NAS Hardening: The Fun Bits&lt;/h2&gt;
&lt;p&gt;The NAS hardening was the meatiest part. We wrote a 10-step plan and worked through it together. Most of it was straightforward—disable SSDP and Avahi, tighten Auto Block, raise the password policy, enforce 2FA. The agent would suggest a change, explain why, and I’d apply it through the DSM UI while the agent verified from the command line.&lt;/p&gt;
&lt;p&gt;But a few moments were genuinely entertaining.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The SSH near-lockout.&lt;/strong&gt; We were hardening &lt;code&gt;sshd_config&lt;/code&gt;—disabling password auth, requiring keys only—and at one point &lt;code&gt;PubkeyAuthentication&lt;/code&gt; got set to &lt;code&gt;no&lt;/code&gt; instead of &lt;code&gt;yes&lt;/code&gt;. Which would have locked me out of my own NAS. Except the agent had suggested earlier in the conversation that I keep a backup SSH session open while making changes. So I did. And that backup session saved me. The lesson went straight into an operational notes doc, and now the &lt;code&gt;nas-manage&lt;/code&gt; skill includes a reminder to always keep a backup session.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The rsync mystery.&lt;/strong&gt; After SSH hardening, every deploy script I have broke. Multiple projects use rsync over SSH to deploy to the NAS, and suddenly none of them worked. We dug into it together and discovered that Synology’s rsync binary is setuid root and uses PAM for authentication—even when it’s invoked over an already-authenticated SSH session. Disabling the Synology rsync service had broken the PAM chain. The fix was simple (re-enable the rsync service), but finding it would have been a solo debugging nightmare. In the conversation, we traced through the PAM config, checked the binary permissions, and figured it out in maybe ten minutes. That one went into the operational notes too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The 2FA cascade.&lt;/strong&gt; After we enabled TOTP for all NAS accounts, the documentation crawl script stopped working because the Synology API now required an OTP code for authentication. That one’s still on the todo list—we noted what broke and moved on. I like that the conversation naturally captured the dependency so future-me won’t have to rediscover it.&lt;/p&gt;
&lt;h2 id=&quot;documentation-just%E2%80%A6-appeared&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/securing-my-home-network-with-ai/#documentation-just%E2%80%A6-appeared&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Documentation Just… Appeared&lt;/h2&gt;
&lt;p&gt;This is the thing I keep coming back to. I didn’t set out to document my network. I set out to make it more secure. But because the conversation naturally involved checking configurations, running API queries, and verifying changes, documentation fell out as a side effect.&lt;/p&gt;
&lt;p&gt;The NAS crawl script hits 80+ Synology API endpoints, and a Python script turns the JSON responses into 24 readable Markdown files covering security, network, Docker, file services, packages, and more. Every time we changed a setting, the natural next step was “let’s re-crawl and make sure the docs reflect reality.” So we did.&lt;/p&gt;
&lt;p&gt;For the Orbi router and AT&amp;amp;T gateway—which don’t have APIs—we built Playwright crawlers that log in, navigate every page, take screenshots, and generate Markdown from the page content. Version-controlled snapshots of every device’s configuration that I can diff over time.&lt;/p&gt;
&lt;p&gt;The improvement plan became a living document too. Eight phases, from the emergency port-forwarding fixes we’d already done through future work like VLAN segmentation, Pi-hole DNS, and a monitoring stack. Each phase has scope, success criteria, and links to the relevant skills and docs. It’s the kind of planning document I’d write for a project at work, and having one for my home network feels like an unexpected luxury.&lt;/p&gt;
&lt;h2 id=&quot;my-favorite-artifact&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/securing-my-home-network-with-ai/#my-favorite-artifact&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; My Favorite Artifact&lt;/h2&gt;
&lt;p&gt;The operational notes document is my favorite thing we produced. It’s a single file capturing every hard-won lesson:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Synology rsync is setuid root and uses PAM—keep the rsync service enabled or deploys break.&lt;/li&gt;
&lt;li&gt;DSM’s “HSTS” checkbox only enables HTTP-to-HTTPS redirect, not the actual &lt;code&gt;Strict-Transport-Security&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;NetBIOS has no separate toggle in DSM 7—it’s tied to the SMB service.&lt;/li&gt;
&lt;li&gt;Docker needs the full &lt;code&gt;/usr/local/bin/docker&lt;/code&gt; path for non-interactive SSH sessions.&lt;/li&gt;
&lt;li&gt;The default-deny firewall rule also blocks ICMP, so add an explicit allow if you want ping monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each one of these is the kind of thing you’d find buried on page three of a forum thread. Having them in a version-controlled file means I won’t rediscover them the hard way, and the AI agent can reference them in future sessions. The knowledge compounds.&lt;/p&gt;
&lt;h2 id=&quot;why-this-was-fun&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/securing-my-home-network-with-ai/#why-this-was-fun&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Why This Was Fun&lt;/h2&gt;
&lt;p&gt;I think what made this project work—and what made it fun instead of tedious—comes down to a few things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It was a conversation, not a checklist.&lt;/strong&gt; I didn’t have to plan everything up front and then execute. I just started talking, and the work emerged naturally. Each discovery led to the next question, which led to the next change.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The project got smarter as we went.&lt;/strong&gt; Every skill we wrote, every operational note we captured, every doc we regenerated made the next session easier. By the end, the agent had enough context about my network to be a genuinely useful collaborator rather than a generic assistant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The outputs were varied and interesting.&lt;/strong&gt; We weren’t just toggling settings. We were building crawlers, writing shell scripts, debugging PAM authentication, designing firewall rules, generating documentation. The variety kept it engaging in a way that grinding through a hardening guide wouldn’t have been.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I stayed in the loop without drowning in details.&lt;/strong&gt; I wasn’t reviewing individual lines of code or verifying command syntax. I was reading the documentation the agent generated, following its explanations of what each change would do, and making decisions based on that. The whole interaction happened in natural language rather than code, which meant I could focus on understanding my network instead of wrestling with configuration syntax. It’s a different kind of understanding than reading every line yourself, but it’s real—and it’s the reason I’d feel confident making changes on my own now.&lt;/p&gt;
&lt;h2 id=&quot;what%E2%80%99s-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/securing-my-home-network-with-ai/#what%E2%80%99s-next&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What’s Next&lt;/h2&gt;
&lt;p&gt;The external attack surface is down to three intentional ports and one annoying DNS issue that needs an architecture change to fix. Router hardening is done—at least as far as the Orbi lets us go. The remaining phases are VLAN segmentation, Pi-hole, monitoring, and eventually some hardware upgrades.&lt;/p&gt;
&lt;p&gt;I’ll keep working through them the same way: start a conversation, let the work emerge, encode what I learn into skills and docs as I go. The harness gets better every session, so each phase should be smoother than the last.&lt;/p&gt;
&lt;p&gt;If you’ve been putting off a project like this because it feels like a slog, try making it a conversation instead. It’s a different experience entirely.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>My First 30 Years in Tech</title>
    <link href="https://jonmagic.com/posts/my-first-30-years-in-tech/"/>
    <updated>2026-01-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/my-first-30-years-in-tech/</id>
    <content type="html">&lt;p&gt;I turned 44 recently, which means I’ve now spent exactly half my professional life as an entrepreneur and half as an employee. Fifteen years building and running my own businesses, followed by fifteen years working for others. The symmetry wasn’t planned, but it’s given me a chance to reflect on what I’ve learned about myself along the way.&lt;/p&gt;
&lt;h2 id=&quot;the-foundation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-first-30-years-in-tech/#the-foundation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Foundation&lt;/h2&gt;
&lt;p&gt;I fell in love with computers when I was five years old. My dad worked at a Kenworth dealership in Florida, and on one visit to his office I got to play Frogger on their ancient machine—probably pre-8088. I thought it was the most amazing thing I’d ever seen.&lt;/p&gt;
&lt;p&gt;When we moved to Michigan, my Uncle John started giving me leftover computer parts from his repair business and swap meets. I’d assemble whatever I could from the scraps. Somewhere around age nine, I entered a home-built PC in the county fair through the 4-H program. I won every award in that category, mostly because I was the only person who had ever entered a computer.&lt;/p&gt;
&lt;p&gt;I come from a family of entrepreneurs. My parents had full-time jobs, but they also ran side businesses—my mom did desktop publishing, my dad was a general contractor. I was homeschooled, which meant I learned to teach myself early. I didn’t actually learn to read until I was eight, but once I did, you couldn’t stop me.&lt;/p&gt;
&lt;p&gt;By eleven or twelve, I was working part-time for my dad’s construction business. If I finished my schoolwork by lunch, I could go swing a hammer at whatever house he was building or renovating. I learned what hard work looked like, and I learned that you could make your own way.&lt;/p&gt;
&lt;h2 id=&quot;the-entrepreneur-phase&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-first-30-years-in-tech/#the-entrepreneur-phase&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Entrepreneur Phase&lt;/h2&gt;
&lt;p&gt;At fourteen, my best friend Christian Metts and I decided to start a &lt;a href=&quot;https://news.ycombinator.com/item?id=40008927&quot;&gt;virtual reality arcade&lt;/a&gt;. This was 1996. We wrote a business plan, raised $10,000 from family and friends, and set up shop in the Jackson Crossing Mall in Jackson, Michigan—right near the nail salon and pet store.&lt;/p&gt;
&lt;p&gt;We had a couple PCs with &lt;a href=&quot;https://en.wikipedia.org/wiki/VFX1_Headgear&quot;&gt;VFX1 headsets&lt;/a&gt; running a game called Descent. It was pretty cool for the time. But that same summer, the Quake demo came out. We spent more time playing Quake than we did selling our service to mall passersby. The business failed by the end of summer. We paid back our investors by working for my dad, swinging hammers and helping build storage units.&lt;/p&gt;
&lt;p&gt;That failure didn’t stop me. I’d already been teaching people how to use computers in exchange for things like horseback riding lessons. I started Legend Computer Services and began doing IT consulting for friends, mostly other homeschool families. After high school, I went to work for a local IT shop. The lead technician quit a few days after I started, so I went from filling ink cartridges to repairing PCs almost overnight.&lt;/p&gt;
&lt;p&gt;The owner was difficult to work for, so I quit a few times and kept doing my own consulting. But I kept going back because I could make more money there than on my own. Eventually I left for good, taking a chunk of the client base with me.&lt;/p&gt;
&lt;p&gt;In 2004, I teamed up with Brad Cochran to buy SabreTech Consulting from a friend who was struggling to make it work. We knew how to make it succeed. A few years later we added Sam Sallows as a partner, and by 2010 we’d grown the business to over a million dollars a year in PC sales and services.&lt;/p&gt;
&lt;h2 id=&quot;the-pivot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-first-30-years-in-tech/#the-pivot&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Pivot&lt;/h2&gt;
&lt;p&gt;Everything changed in 2006 when Christian Metts—same friend from the VRcade days—introduced me to &lt;a href=&quot;https://rubyonrails.org/&quot;&gt;Ruby on Rails&lt;/a&gt;. I went to the first RailsConf in Chicago that year and caught the programming bug. We started building software for SabreTech customers: a billing sync system for a chain of tanning salons, an obituary website called &lt;a href=&quot;https://jonmagic.com/posts/forever-remember-me/&quot;&gt;Forever Remember Me&lt;/a&gt;, internal tools for our own operations.&lt;/p&gt;
&lt;p&gt;In 2007, my wife Natalie and I got married and moved to Elkhart, Indiana. I searched for “ruby south bend” and found a meetup at Notre Dame. That’s where I met John Nunemaker and Steve Smith.&lt;/p&gt;
&lt;p&gt;We started hanging out regularly, hacking together at a place called Fiddler’s Hearth in South Bend. One day they were complaining about Slideshare. One of us said, “If it sucks so much, why don’t we build our own?” I pulled out my laptop, figured out how to convert PDFs to images with ImageMagick, and &lt;a href=&quot;https://jonmagic.com/posts/the-history-of-speaker-deck/&quot;&gt;Speaker Deck was born&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Steve and John had started a company called Ordered List. They were building products like Harmony (a CMS) and doing consulting work. In late 2010, they offered me a job.&lt;/p&gt;
&lt;p&gt;This was a big decision. I’d been an entrepreneur for fifteen years. The idea of working for someone else felt foreign. But with Natalie’s support, I sold my share of SabreTech to my partners and &lt;a href=&quot;https://jonmagic.com/posts/hey-mom-i-got-a-job/&quot;&gt;joined Ordered List&lt;/a&gt; in December 2010. Brandon Keepers joined a few weeks later, then Matt Graham a couple months after that.&lt;/p&gt;
&lt;h2 id=&quot;the-github-chapter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-first-30-years-in-tech/#the-github-chapter&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The GitHub Chapter&lt;/h2&gt;
&lt;p&gt;Our small team built Gauges (a web analytics tool), maintained Speaker Deck and Harmony, and paid the bills with consulting work—including helping Zynga build Words with Friends for Facebook.&lt;/p&gt;
&lt;p&gt;GitHub noticed our products and our work. They made an offer to acquire Ordered List. On December 5th, 2011, &lt;a href=&quot;https://jonmagic.com/posts/githubber/&quot;&gt;all five of us joined GitHub&lt;/a&gt;. I became employee #50.&lt;/p&gt;
&lt;p&gt;I’d been an early GitHub user—user ID 623, signed up on February 22nd, 2008—back when the platform first launched. Being part of the Ruby community meant you found out about GitHub quickly. Now I was an early employee too, just three years into the company’s life.&lt;/p&gt;
&lt;h2 id=&quot;the-realization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-first-30-years-in-tech/#the-realization&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Realization&lt;/h2&gt;
&lt;p&gt;I’ve now been at GitHub for fourteen years, and an employee for fifteen. The symmetry with my entrepreneur years is complete.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here’s what I’ve discovered: I love building software more than I love running a business. But it’s more specific than that. I love building teams that solve people’s problems through software.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/my-first-30-years-in-tech/orderedlist-octocat-with-vignettes.webp&quot; alt=&quot;orderedlist octocat with vignettes&quot; /&gt;&lt;/p&gt;
&lt;p&gt;At GitHub I’ve had the chance to serve our support team, finance team, sales team, product team, and security team by designing, planning, building, and maintaining software. I’ve built and led teams. I’ve found my calling.&lt;/p&gt;
&lt;p&gt;But it’s not just the work—it’s where I get to do it. I’ve &lt;a href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/&quot;&gt;interviewed at other companies&lt;/a&gt; every few years since joining GitHub, and I keep choosing to stay. There’s something special about being at the center of the software universe. I love helping developers—and people who don’t yet know they’re about to become developers—discover and invent a new world. GitHub brings people together. It gives them the opportunity to do meaningful work through collaboration by solving problems together. It’s hard for me to explain the fulfillment I get from contributing to the open source projects and the infrastructure that power everything from research to startups to enterprises—and through protecting that community so it can thrive.&lt;/p&gt;
&lt;p&gt;Software development is my calling and GitHub is a huge part of that—and a central part of my identity.&lt;/p&gt;
&lt;p&gt;I don’t have grand lessons to share. Just this: reflection matters. I didn’t know what I truly loved until I’d spent fifteen years doing one thing and fifteen years doing another. Sometimes you have to live both paths to understand which one fits.&lt;/p&gt;
&lt;p&gt;I hope I get another thirty years doing this work. I want to keep waking up every morning trying to figure out the next cool problem to solve with technology—without necessarily having to worry about all the details of running a business. I want to focus on building teams that help people.&lt;/p&gt;
&lt;p&gt;That’s what the first thirty years taught me about myself.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Turning Agent Misses into Systemic Improvements</title>
    <link href="https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/"/>
    <updated>2025-12-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/</id>
    <content type="html">&lt;p&gt;Over the holiday break I decided to rebuild a slice of an internal web app from my day job as a webview experience inside VS Code. The goal wasn’t really the feature itself—it was to force myself to learn the &lt;a href=&quot;https://code.visualstudio.com/api&quot;&gt;VS Code extension APIs&lt;/a&gt; and to get my hands dirty with &lt;a href=&quot;https://github.com/open-truss/open-truss&quot;&gt;Open Truss&lt;/a&gt;, an open-source workflow framework I’ve been collaborating on with &lt;a href=&quot;https://github.com/hktouw&quot;&gt;@hktouw&lt;/a&gt; and &lt;a href=&quot;https://github.com/kmcq&quot;&gt;@kmcq&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I started where I usually do: drafting a plan, spinning up a workspace, and asking Copilot to start coding. &lt;em&gt;But as I worked I got annoyed with doing things the way I’ve been doing them the past year—constantly steering the agent, pasting browser console errors, describing visual bugs, and nudging it back on track.&lt;/em&gt; The loop I’d used for most of 2025 now felt too fragile.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/turning-agent-misses-into-systemic-improvements/jonmagic-and-copilots-at-the-software-assembly-line.webp&quot; alt=&quot;jonmagic standing at the software assembly line with agents working the line&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Then I watched &lt;a href=&quot;https://www.youtube.com/watch?v=rIrxkB-02P0&quot;&gt;this interview&lt;/a&gt; about &lt;a href=&quot;https://agentskills.io/&quot;&gt;SKILLS.md&lt;/a&gt; in Copilot, learned about the &lt;a href=&quot;https://ghuntley.com/ralph/&quot;&gt;Ralph Wiggum AI technique&lt;/a&gt;, read &lt;a href=&quot;https://heidloff.net/article/why-agents-fail/&quot;&gt;Niklas Heidloff’s post from March 2025 on why agents fail&lt;/a&gt;, and &lt;a href=&quot;https://bits.logic.inc/p/ai-is-forcing-us-to-write-good-code&quot;&gt;Steve Krenzel’s piece on the infrastructure tax teams should pay&lt;/a&gt;, and a few things started to click.&lt;/p&gt;
&lt;h2 id=&quot;the-shift&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/#the-shift&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Shift&lt;/h2&gt;
&lt;p&gt;I was spending more time debugging the agent than building features. The loop went like this: prompt Copilot, review the output, find the bug, explain what went wrong, try again. I was the debugger, and every iteration took seconds or minutes because I had to context-switch between the code, the terminal, and the running VS Code extension.&lt;/p&gt;
&lt;p&gt;Then I changed one thing. Instead of just fixing what broke, I started asking: &lt;strong&gt;what didn’t the agent see?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If it hallucinated a GraphQL field, the schema wasn’t visible. If it picked the wrong component, the registry docs were incomplete. If the layout looked wrong, there was no visual gate. Each failure pointed to missing observability or incomplete instructions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So I stopped treating agent misses as bugs to fix and started treating them as gaps to close. Every mistake became a reason to add a test or eslint rule, document a pattern in a skill, or tighten the instructions. The work shifted—less “write this code for me” and more “here’s how to see when you’re wrong.”&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-little-setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/#a-little-setup&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; A Little Setup&lt;/h2&gt;
&lt;p&gt;Before we dive into the examples below let me explain a bit about the project I was working on. It’s a web-based Kafka consumer monitoring tool that engineer first responders use to debug stream processing issues—checking consumer lag, partition assignments, offset tracking, etc.&lt;/p&gt;
&lt;p&gt;The existing web app worked fine, but it lived in a browser tab that engineers had to context-switch to. I wanted to bring those affordances into the editor closer to where the changes to address issues actually happens. Click a consumer name in your code, see its current state, jump to logs or metrics—all without leaving VS Code.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;I think about the intersection of internal tools and AI a lot, so this project was a good fit to see how deeply I can integrate agents and mcp tools into the workflows my stakeholders (analysts, support staff, first responders) use every day. I chose &lt;a href=&quot;https://github.com/open-truss/open-truss&quot;&gt;Open Truss&lt;/a&gt; because we designed it to empower non-engineers to build internal tools with minimal coding, and I wanted to see how AI agents could help fill in the gaps.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I also setup this particular project with three distinct agents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Planner&lt;/strong&gt;: An agent that breaks down high-level feature requests into discrete implementation steps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Implementer&lt;/strong&gt;: An agent that writes the code based on high-level feature requests.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Reviewer&lt;/strong&gt;: An agent that reviews the Implementer’s code for correctness, style, and adherence to best practices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;turning-misses-into-hits&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/#turning-misses-into-hits&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Turning Misses into Hits&lt;/h2&gt;
&lt;p&gt;Here are a few examples of how I turned agent misses into systemic improvements that made future iterations smoother.&lt;/p&gt;
&lt;h3 id=&quot;example-1%3A-hallucinated-graphql-fields&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/#example-1%3A-hallucinated-graphql-fields&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Example 1: Hallucinated GraphQL Fields&lt;/h3&gt;
&lt;p&gt;The first systemic failure showed up early. The Implementer built a consumer list workflow and wrote a GraphQL query to fetch consumer data:&lt;/p&gt;
&lt;pre class=&quot;language-graphql&quot;&gt;&lt;code class=&quot;language-graphql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;token definition-query function&quot;&gt;AppConsumers&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token object&quot;&gt;appConsumers&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token object&quot;&gt;consumers&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;consumerName&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;groupId&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;status&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;# ✗ ERROR&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When I ran the workflow, it crashed with a schema error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[GraphQL] Cannot query field &amp;quot;status&amp;quot; on type &amp;quot;AppConsumer&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I asked Copilot to help me understand what went wrong. It found that the &lt;code&gt;status&lt;/code&gt; field existed on the parent response object (&lt;code&gt;AppConsumersResponse&lt;/code&gt;), not on individual consumers.&lt;/p&gt;
&lt;p&gt;I could’ve just asked Copilot to fix the query and moved on. Instead, I asked: &lt;strong&gt;what’s preventing the agent from seeing this before it writes the code?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The schema file lived in &lt;code&gt;generated/schema.graphql&lt;/code&gt;—96,000 lines synced from the backend. The agent wasn’t checking it. So I asked Copilot to build a skill that codified the validation workflow:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;From &lt;code&gt;.github/skills/graphql-schema-validation/SKILL.md&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Critical Rule&lt;/span&gt;
&lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;ALWAYS verify GraphQL queries against the actual schema before implementation.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; Step 4: Search the Schema&lt;/span&gt;
Use grep to find type definitions:

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; Find a type definition&lt;/span&gt;
grep -A 10 &quot;^type AppConsumer {&quot; generated/schema.graphql&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Example output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-graphql&quot;&gt;&lt;code class=&quot;language-graphql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppConsumer&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;consumerName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice: No &lt;code&gt;status&lt;/code&gt; field exists on &lt;code&gt;AppConsumer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then I had Copilot add it to the agent instructions:&lt;/p&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;GraphQL queries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;: Always validate against the schema before writing queries.
  Use grep to verify field existence on target types. Never assume field availability.
  See &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`graphql-schema-validation`&lt;/span&gt; skill.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next time the Implementer needed to write a query, it ran &lt;code&gt;grep -A 10 &amp;quot;^type ConsumerPartition {&amp;quot; generated/schema.graphql&lt;/code&gt; first, saw which fields actually existed, and got it right. No hallucinations. No runtime crashes.&lt;/p&gt;
&lt;h3 id=&quot;example-2%3A-stale-renders-from-missing-usesignals()&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/#example-2%3A-stale-renders-from-missing-usesignals()&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Example 2: Stale Renders from Missing &lt;code&gt;useSignals()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A few days in, I noticed a pattern. The agent would build a component that read from a signal prop—say, a table that displays consumer data from &lt;code&gt;:consumerData&lt;/code&gt;—and the table would render once with empty data, then never update when the signal changed.&lt;/p&gt;
&lt;p&gt;Here’s what the component looked like:&lt;/p&gt;
&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ConsumerTable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; dataSignal &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; dataSignal&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Consumer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dataSignal&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Table&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;TableRow&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;TableRow&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Table&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The data would load, the signal would update, but the table stayed frozen on “No data found.”&lt;/p&gt;
&lt;p&gt;The problem: Open Truss signals use Preact signals under the hood. React doesn’t automatically subscribe to &lt;code&gt;.value&lt;/code&gt; changes unless you call &lt;code&gt;useSignals()&lt;/code&gt; at the top of the component (at least the way we’re using it right now). Without it, you get stale renders.&lt;/p&gt;
&lt;p&gt;I could’ve just added the hook and moved on. But I’d already debugged this three times that week. So I asked: &lt;strong&gt;how do I make this failure impossible?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Copilot updated the component-wrapper skill with a clear warning:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;From &lt;code&gt;.github/skills/open-truss.component-wrapper/SKILL.md&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; ⚠️ Signal-aware components MUST call `useSignals()`&lt;/span&gt;

If a component &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;reads or writes any signal prop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; (props passed as &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`:signalName`&lt;/span&gt;),
call &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`useSignals()`&lt;/span&gt; at the top of the function body &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; deriving values or rendering.

import { useSignals } from &#39;@open-truss/open-truss&#39;

export function MySignalConsumer({ valueSignal }: { valueSignal: { value?: string } }) {
  useSignals()  // ← Required for reactivity
  const value = valueSignal?.value ?? &#39;&#39;
  return &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{value}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
}

Missing &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`useSignals()`&lt;/span&gt; leads to stale renders (tables showing &quot;No data found&quot;,
badges not updating, etc.) even though the signal value changes.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it added it to the checklist at the bottom of the skill:&lt;/p&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; [ ] &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`useSignals()`&lt;/span&gt; is called when any prop is a signal reference (reads/writes &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`:signalName`&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, every new component got it right on the first try. The agent would see the warning, add the hook, and the stale render bug vanished.&lt;/p&gt;
&lt;h3 id=&quot;example-3%3A-test-harness-first%2C-features-second&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/#example-3%3A-test-harness-first%2C-features-second&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Example 3: Test Harness First, Features Second&lt;/h3&gt;
&lt;p&gt;Manual testing was killing me. I’d ask the agent to build a feature, press F5 to launch the VS Code development window, click around, find a bug, describe it back to the agent, and repeat. The loop took seconds of my time per iteration.&lt;/p&gt;
&lt;p&gt;I asked Copilot to build a Playwright harness that ran Open Truss workflows in a real browser, mocking the VS Code boundary. Now every workflow got a co-located test file that ran &lt;em&gt;before&lt;/em&gt; I ever opened VS Code:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// workflows/consumer-detail.test.ts&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;detail tab opens with correct args&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; page &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Listen for VS Code command before clicking&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; commandPromise &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;vscode-command&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;detail&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; once&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[data-testid=&quot;consumer-row-1&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; command &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; commandPromise
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;command&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;command&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;app.openWorkflow&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;command&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;workflow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;consumer-detail&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;command&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;consumerName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;signal-processor&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This became a gate: the Implementer couldn’t claim a feature was done until this test passed. No test, no merge. The payoff showed up immediately—test failures told me &lt;em&gt;exactly&lt;/em&gt; which assertion broke, not just “it doesn’t work.”&lt;/p&gt;
&lt;h3 id=&quot;example-4%3A-visual-qa-catches-what-dom-assertions-miss&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/#example-4%3A-visual-qa-catches-what-dom-assertions-miss&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Example 4: Visual QA Catches What DOM Assertions Miss&lt;/h3&gt;
&lt;p&gt;After getting tests passing, I kept finding AI generated UI slop that DOM checks couldn’t catch: large gaps between components, weird alignment, UI that just didn’t make sense. So I asked Copilot to add a visual QA step leveraging the &lt;a href=&quot;https://github.com/simonw/llm&quot;&gt;llm cli&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;consumer badges have consistent spacing&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; page &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; screenshot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;screenshot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runVisualQA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    screenshot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    criteria&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;Status badges have 16px horizontal gap between them&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;No badges overlap or clip&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;Badge text is readable and not truncated&#39;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;gpt-4.1&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;verdict&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;pass&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;runVisualQA&lt;/code&gt; function captures the screenshot and pipes it to a headless reviewer that checks for overlap, clipping, and visual affordances. Now visual correctness became data, not vibes. Copilot even added this to the workflow spacing skill so future implementations got it right from the start.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-warning&quot;&gt;&lt;p&gt;You should disable this for CI unless you like to 🔥💵&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;what-i-learned&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/#what-i-learned&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What I Learned&lt;/h2&gt;
&lt;p&gt;Over the last few days of this project, I shipped roughly equal amounts of features and guardrails. Looking at the git log, the commits cluster into three arcs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Features&lt;/strong&gt;: Kafka consumer monitoring, list/detail splits, templated links, new tab routing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observability + guardrails&lt;/strong&gt;: Visual QA hooks, workflow spacing standards, registry validation tests&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enablement plumbing&lt;/strong&gt;: Composite builds, schema sync, test harnesses, agent skills&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The payoff was measurable. Human-in-the-loop density dropped from &lt;em&gt;every few minutes&lt;/em&gt; to &lt;em&gt;once per slice.&lt;/em&gt; The Implementer could take a high-level feature request and deliver working code with minimal back-and-forth. The agents made fewer mistakes because they could see their failures.&lt;/p&gt;
&lt;p&gt;Each failure turned into improved observability, a new skill, or clearer instructions. Those improvements compounded. By week two, features that would’ve taken five to ten rounds of steering are landing in one or two.&lt;/p&gt;
&lt;h2 id=&quot;what%E2%80%99s-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/turning-agent-misses-into-systemic-improvements/#what%E2%80%99s-next&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What’s Next&lt;/h2&gt;
&lt;p&gt;Now I’m teaching my implementation and review agents to tell me about ways to improve themselves. I want them to suggest updates to the skills they use. The goal is a self-improving AI collaborator that gets better at building software with each iteration, not just faster at writing code.&lt;/p&gt;
&lt;p&gt;A lot of the &lt;a href=&quot;https://news.ycombinator.com/item?id=46426624&quot;&gt;vocal community is exploring memory systems&lt;/a&gt;—databases that persist agent context across sessions, semantic search over past decisions, knowledge graphs of what was learned. That approach treats agent failures as a recall problem: if only the agent remembered the last time it made this mistake, it wouldn’t repeat it.&lt;/p&gt;
&lt;p&gt;For now at least I’m going the opposite direction. Every time the agent sees my project with fresh eyes, it’s testing whether the codebase is clear enough to guide a newcomer. If it keeps hitting the same GraphQL field hallucination, that’s not a memory gap—it’s missing observability. The schema validation skill I built isn’t a workaround for forgetfulness; it’s a permanent improvement that makes that entire class of failure impossible.&lt;/p&gt;
&lt;p&gt;If you’re building with agents, stop trying to prompt your way out of the same agent misses over and over. Build the observability they need to see the world clearly and the skills to improve themselves.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>How I Work, 2025 Edition</title>
    <link href="https://jonmagic.com/posts/how-i-work-2025-edition/"/>
    <updated>2025-12-16T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/how-i-work-2025-edition/</id>
    <content type="html">&lt;p&gt;I took this week off to reflect and spend some time closer to the mountains as I start my forty-fourth year on this planet. One of the things I’ve been thinking about and have been meaning to write about is how my processes and tools have evolved over the past two decades.&lt;/p&gt;
&lt;p&gt;Most productivity systems, the processes and tools, optimize for the wrong brain—someone else’s. I spent years trying to adopt systems that worked for the people I look up to because of their brilliance and productivity but time after time I abondoned the prescribed workflows. They just didn’t stick for one reason or another.&lt;/p&gt;
&lt;p&gt;Eventually I realized that my brain, not theirs, is what I should be designing for. I still look to others for new ideas and optimizations but now I time box my evaluation and then adapt or abandon.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/how-i-work-2025-edition/reflecting-and-enjoying-a-whiskey.webp&quot; alt=&quot;jonmagic enjoying a whiskey&quot; /&gt;&lt;/p&gt;
&lt;p&gt;That is probably one of the most important things I can share in this post, that optimizing how you work isn’t something you tackle in a weekend and then you’re done. It’s a marathon of experimentation, reflection, and adaptation.&lt;/p&gt;
&lt;p&gt;Our brains are constantly changing as they consume new information, and we experience chemical changes due to aging, so the process is necessarily lifelong and iterative. The tools and processes that work for you today may not work for you in a year or two. You have to keep tuning and adapting.&lt;/p&gt;
&lt;p&gt;This post is a reflection on how I work at the end of 2025, some of it new, but lots of it old.&lt;/p&gt;
&lt;h2 id=&quot;two-mental-frameworks-i-consistently-use&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/how-i-work-2025-edition/#two-mental-frameworks-i-consistently-use&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Two Mental Frameworks I Consistently Use&lt;/h2&gt;
&lt;p&gt;There are two primary frameworks I use day to day, week to week, month to month, and year to year to keep myself organized and productive.&lt;/p&gt;
&lt;h3 id=&quot;prime&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/how-i-work-2025-edition/#prime&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; PRIME&lt;/h3&gt;
&lt;p&gt;Five verbs shape my week. I use them to guide my weekly planning and daily execution.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Plan&lt;/strong&gt;: Reduce ambiguity by formulating a narrative arc and naming what “better” looks like.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refine&lt;/strong&gt;: Shorten loops by improving tools, templates, and paved paths.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrate&lt;/strong&gt;: Connect efforts across teams, carry context, and make status legible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mentor&lt;/strong&gt;: Grow people via pairing, reviews, and unblocking; learn out loud together.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Execute&lt;/strong&gt;: Ship the smallest credible artifact that forces a decision.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These five words are somewhat of a mantra for me (a term I first learned about from &lt;a href=&quot;https://ecorner.stanford.edu/wp-content/uploads/sites/2/2004/10/1172.pdf&quot;&gt;Guy Kawasaki&lt;/a&gt; more than two decades ago). My mantra from 2020 to 2024 was “I will listen, I will learn, I will teach, and I will serve”.&lt;/p&gt;
&lt;p&gt;It sounds silly but this little exercise has helped me maintain focus throughout a day, a week, a month, and even a year or more. My brain spends less time traveling down counter producive paths when I can return to these five words to reorient myself.&lt;/p&gt;
&lt;h3 id=&quot;swot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/how-i-work-2025-edition/#swot&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; SWOT&lt;/h3&gt;
&lt;p&gt;My mantra is a direct result of me consistently analyzing myself using a framework like SWOT (Strengths, Weaknesses, Opportunities, Threats). When I first learned about the &lt;a href=&quot;https://jonmagic.com/posts/swot-analysis/&quot;&gt;SWOT analysis framework&lt;/a&gt; in college I started applying it once or twice a year to my personal and professional life with great results. Over time I’ve used it more frequently to the point where it’s part of my daily mental model driving how I think and make decisions.&lt;/p&gt;
&lt;p&gt;There are other great frameworks like SOAR (Strengths, Opportunities, Aspirations, Results) that focus more on the positive. SWOT always stuck for me because I learned it first but I think the important thing is finding a repeatable mental model that helps guide decisions and trade-offs consistently.&lt;/p&gt;
&lt;h2 id=&quot;my-workflow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/how-i-work-2025-edition/#my-workflow&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; My Workflow&lt;/h2&gt;
&lt;p&gt;My workflow centers on a single folder I call my &lt;em&gt;brain&lt;/em&gt;—a directory of Markdown files that starts with a &lt;code&gt;Weekly Notes/Week of &amp;lt;yyyy-mm-dd&amp;gt;.md&lt;/code&gt; file for each week which then flow into &lt;code&gt;Meeting Notes/&amp;lt;handle&amp;gt;.md&lt;/code&gt; files, which wikilink to &lt;code&gt;Transcripts/&amp;lt;yyyy-mm-dd&amp;gt;/&amp;lt;nn&amp;gt;.md&lt;/code&gt; and &lt;code&gt;Executive Summaries/&amp;lt;yyyy-mm-dd&amp;gt;/&amp;lt;nn&amp;gt;.md&lt;/code&gt; files, and then into &lt;code&gt;Daily Projects/&amp;lt;yyyy-mm-dd&amp;gt;/&lt;/code&gt; folders for day-level scratchpads and context dumps.&lt;/p&gt;
&lt;p&gt;On Sunday evening, I open VS Code Insiders and run a single command from a custom VS Code extension (I had Copilot help me build) to create my new &lt;code&gt;Week of ...&lt;/code&gt; file from a template. Then I do something deliberately manual, I open my calendar and manually type in each meeting in the Weekly Notes file and block out focus time on the calendar. This takes about ten minutes and feels like a warm-up before a run. By the time I’m done, my brain holds the week’s shape—meetings clustered here, deep work carved out there, the main threads I’ve chosen to move forward sitting at the top.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/how-i-work-2025-edition/weekly-note.webp&quot; alt=&quot;example weekly note&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Manual priming helps me create the narrative arc. Automation could populate my schedule faster, but I wouldn’t remember it. The friction is the feature.&lt;/p&gt;
&lt;p&gt;During this priming process I’ll often use Copilot in VS Code to help me remember things I’ve been working on recently and try to find interconnections and opportunities to integrate work across teams. The ideas from this often feed back into my calendar as new meetings or checkpoints.&lt;/p&gt;
&lt;p&gt;Everything throughout the week now flows from this single source of truth.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Folder&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Weekly Notes&lt;/td&gt;
&lt;td&gt;Planning, goals, schedule, and backlinks to meetings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Meeting Notes&lt;/td&gt;
&lt;td&gt;Rolling notes with newest sections at top&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily Projects&lt;/td&gt;
&lt;td&gt;Day-level staging: scratch pads, transcripts, context dumps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transcripts&lt;/td&gt;
&lt;td&gt;Raw meeting transcripts before summarization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Executive Summaries&lt;/td&gt;
&lt;td&gt;Distilled updates for leadership&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Projects&lt;/td&gt;
&lt;td&gt;Multi-week initiatives with numbered working notes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snippets&lt;/td&gt;
&lt;td&gt;Weekly accomplishments: Ships, Risks, Collaborations, Shoutouts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Archive&lt;/td&gt;
&lt;td&gt;Cold storage after things have aged out of usefulness for the current year&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The structure matters less than the organizing principles that make it fast. For example with Meeting Notes I keep the most recent content at the top. When I open a Meeting Notes file, or when Copilot does, the first screen shows what matters most right now. Historical context is there when I need it, but I don’t have to scroll past it to remember what happened yesterday.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;Since I’m working in VS Code I can give it &lt;a href=&quot;https://code.visualstudio.com/docs/copilot/customization/custom-instructions#_use-a-githubcopilotinstructionsmd-file&quot;&gt;custom Copilot instructions&lt;/a&gt; and you can see my current iteration &lt;a href=&quot;https://gist.github.com/jonmagic/a7916bfb5505560f0bf1dba3e76f93fa&quot;&gt;here&lt;/a&gt;. &lt;a href=&quot;https://gist.github.com/jonmagic/a7916bfb5505560f0bf1dba3e76f93fa&quot;&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/how-i-work-2025-edition/copilot-instructions.webp&quot; alt=&quot;copilot-instructions.md&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I use &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=svsool.markdown-memo&quot;&gt;wikilinks&lt;/a&gt; instead of duplicating content. When I need to reference a decision or a meeting, I link to its source rather than restating it. The trail of breadcrumbs matters because both future-me and my AI agents follow the same path. If I can’t trace how I arrived at a conclusion, I probably don’t understand it well enough yet.&lt;/p&gt;
&lt;p&gt;Numbered prefixes on files encode creation order within a day or project folder. &lt;code&gt;01 focus.md&lt;/code&gt;, &lt;code&gt;02 pairing notes.md&lt;/code&gt;, &lt;code&gt;03 random idea.md&lt;/code&gt;. This sounds fussy, but it makes keyboard-driven scanning instant. I know &lt;code&gt;01&lt;/code&gt; was my starting point and &lt;code&gt;05&lt;/code&gt; was where I landed after four pivots. The numbers tell a story even before I open the files.&lt;/p&gt;
&lt;h3 id=&quot;why-markdown-in-vs-code%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/how-i-work-2025-edition/#why-markdown-in-vs-code%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Why Markdown in VS Code?&lt;/h3&gt;
&lt;p&gt;I’ve tried plenty of alternatives over the past two decades—Notion, Obsidian, Apple Notes, and yes, GitHub Projects for task tracking. Each has merits, but they all introduced friction that slowed me down because of how my mental and physical muscles work.&lt;/p&gt;
&lt;p&gt;Web-based tools lock me into connectivity requirements and proprietary formats that concern me for long-term retention. GitHub Projects is powerful for cross-team visibility, but the overhead of maintaining another system rarely pays off when I already have my brain folder working well.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;I ask myself one question when evaluating any tool or process: does this shorten my loop from idea to artifact to decision? If I can’t answer yes, I’m probably adding decoration.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;GitHub Flavored Markdown in VS Code wins for me because it’s fast, &lt;a href=&quot;https://en.wiktionary.org/wiki/diffable&quot;&gt;diffable&lt;/a&gt; (easy to compare changes between versions), searchable, and works offline. AI agents can read and write files directly, which lets me delegate grunt work without switching contexts. The format will outlive any single app, and if I ever need to migrate, the files are just text.&lt;/p&gt;
&lt;p&gt;I do use a folder syncing tool to keep my brain accessible across my devices so I can read and write markdown files from my iPhone as needed, but my primary user interface is VS Code Insiders on a Macbook Pro M1.&lt;/p&gt;
&lt;h2 id=&quot;optimizing-execution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/how-i-work-2025-edition/#optimizing-execution&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Optimizing Execution&lt;/h2&gt;
&lt;p&gt;Every day I create anywhere from one to dozens of Daily Project files to act as scratchpads for each idea I’m pursuing. After creating a file in Daily Projects (also using the custom VS Code extension I have in my &lt;code&gt;brain&lt;/code&gt; folder) I almost always turn to Copilot as a pair partner to help me start collecting artifacts, sifting through details, and formulating ideas or final outputs.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;I have Copilot choose the model by setting it to Auto mode (h/t &lt;a href=&quot;https://brittanyellich.com/agentic-software-development/&quot;&gt;Brittany Ellich&lt;/a&gt;) and it works surprisingly well.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;When I’m working across multiple repositories—which is most of the time these days—I use &lt;a href=&quot;https://github.com/jonmagic/workspace-manager&quot;&gt;a CLI tool I built&lt;/a&gt; to spin up &lt;a href=&quot;https://code.visualstudio.com/docs/editing/workspaces/workspaces&quot;&gt;VS Code Workspaces&lt;/a&gt; with git worktrees. I tell Copilot “start a workspace with these projects,” and it uses the cli to find the projects on disk, creates worktrees for each, and drops them all into a single VS Code Workspace. The friction of juggling branches across repos disappears, and Copilot can now search or change code across all of them in one session.&lt;/p&gt;
&lt;p&gt;GitHub remains my system of record for anything collaborative: Issues, Pull Requests, Discussions, and a little bit of Projects when the coordination benefit outweights the maintenance cost.&lt;/p&gt;
&lt;h3 id=&quot;walk-%E2%86%92-think-%E2%86%92-write&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/how-i-work-2025-edition/#walk-%E2%86%92-think-%E2%86%92-write&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Walk → Think → Write&lt;/h3&gt;
&lt;p&gt;Some of my best thinking happens away from the keyboard and the distractions email and chat. When I’m stuck on a design problem or trying to work out the narrative arc of a post, I’ll often &lt;a href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#the-minimal-reproducible-stack&quot;&gt;grab my phone and go for a walk&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/how-i-work-2025-edition/walking-and-talking-and-then-typing.webp&quot; alt=&quot;Walk and talk&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I record a voice memo—just talking through the problem out loud, no script, no editing. Sometimes it’s coherent, sometimes it’s a mess. Doesn’t matter. Most of the source of this post was created from the transcripts of walks I took along the Truckee River this week while visiting Reno Nevada.&lt;/p&gt;
&lt;h2 id=&quot;closing-the-loop&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/how-i-work-2025-edition/#closing-the-loop&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Closing the Loop&lt;/h2&gt;
&lt;p&gt;Last year I didn’t capture all of these artifacts. Meetings would happen, decisions would get made, and a week later I’d be piecing together what we agreed to from memory, Issues, and stray Slack messages. Reflection was exhausting because I had no artifacts to base my reflections on.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/&quot;&gt;Now I capture everything&lt;/a&gt;. After every meeting, &lt;a href=&quot;https://github.com/jonmagic/scripts?tab=readme-ov-file#archive-meeting&quot;&gt;I run a script&lt;/a&gt; that grabs the transcript, generates an executive summary, and updates my &lt;code&gt;Meeting Notes/&amp;lt;person&amp;gt;.md&lt;/code&gt; file with a new date section at the top—wikilinks to the transcript and summary, plus a few bullets on decisions and follow-ups. The whole thing takes maybe thirty seconds.&lt;/p&gt;
&lt;p&gt;When I sit down with Copilot to write my weekly snippets or prep for a retro, I’m not reconstructing memory. I’m reviewing artifacts I created in real time: closed PRs, meeting summaries, Daily Projects files. Copilot can pull from all of it because it’s already written down and organized. The collaborative reflection part—“what themes do you see across these meetings?” or “what shipped that moved our OKRs forward?”—is easy now because the raw material is sitting there waiting.&lt;/p&gt;
&lt;p&gt;Each week I write snippets. What shipped, what’s risky, what’s blocked, new ideas, who I collaborated with, who deserves a shoutout. Later when I need promotion materials or I’m prepping for a semester retro, I have months of weekly artifacts to pull from instead of a blank page and a vague sense of “I think I did some stuff.”&lt;/p&gt;
&lt;p&gt;The reason this works for me is that each piece serves multiple purposes. Meeting Notes, Issues, and Pull Requests feed snippets, snippets feed retros, retros shape next semester’s planning. I’m building on what’s already there instead of starting from scratch every time.&lt;/p&gt;
&lt;h2 id=&quot;what%E2%80%99s-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/how-i-work-2025-edition/#what%E2%80%99s-next&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What’s Next&lt;/h2&gt;
&lt;p&gt;Next up is working through current friction points including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Workspace Manager (VS Code Workspaces + git worktrees) works well for multi-repo projects, but running the same app in multiple workspaces creates port conflicts (dev servers, databases, other dependencies). I’m evaluating devcontainers and other isolation strategies to fix this.&lt;/li&gt;
&lt;li&gt;In-person meetings are clunky to turn into usable transcripts. I record on my phone and run it through MacWhisper, but labeling speakers and threading context is still too manual. I haven’t found a flow that feels as smooth as labeled transcripts in Zoom or Teams.&lt;/li&gt;
&lt;li&gt;I’m using Microsoft Teams and M365 more and more for work and feeling some pain. I imagine that will continue for a bit (new UX, new defaults, new bugs), but it also opens doors: maybe I can stop manually starting transcripts, maybe I can wire Teams events straight into my meeting-notes workflow. I’ll report back once I stub my toe a few times 😅&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I love learning about how other people work so &lt;a href=&quot;mailto:jonmagic@gmail.com&quot;&gt;please send me&lt;/a&gt; your favorite tools, processes, or mental models! Happy Holidays 🎊&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Building Career Security in an Uncertain World</title>
    <link href="https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/"/>
    <updated>2025-10-23T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/</id>
    <content type="html">&lt;p&gt;Earlier today I saw a friend post about layoffs. Someone they were collaborating with on a project had just been let go. “I will be anxiously distracted for the next few days,” they wrote, “trying to yet again pivot a collaboration I was planning on.”&lt;/p&gt;
&lt;p&gt;The conversation that followed touched on questions many of us are wrestling with right now. How can critical engineering positions get cut when security issues are mounting? Why plan a project if the people who can execute it aren’t considered essential? And underneath those tactical questions sat a deeper, more personal one: Am I next?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/building-career-security-in-an-uncertain-world/walk-and-talk.webp&quot; alt=&quot;walking and talking about job security&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I wanted to respond with empathy, but also with something useful, so I shared a few thoughts in the moment and then started working on this post.&lt;/p&gt;
&lt;p&gt;Their frustration is completely valid—the randomness of layoffs makes planning feel futile. But I’ve learned something over nearly 14 years at GitHub and 28 years in tech that might help. Job security doesn’t exist. It never did. Companies make decisions that don’t make business sense to those on the ground. Layoffs happen even when the work is critical. The promise of a stable position is always fragile.&lt;/p&gt;
&lt;p&gt;But career security? That’s real to a degree. And it’s built through deliberate practice, not by holding tight to any single job.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p&gt;&lt;strong&gt;Feedback I received on this post:&lt;/strong&gt; when it feels like things are going sideways make sure to “take 5min to check-in with yourself and name what are you feeling in the moment instead of catastrophizing in your head. It gives a more clear perspective of what steps you have access to do next.”&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;the-uncomfortable-truth&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#the-uncomfortable-truth&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Uncomfortable Truth&lt;/h2&gt;
&lt;p&gt;I’ve watched this cycle play out more times than I can count. Earlier this year, we lost three teammates on my own team at GitHub to layoffs. Amazing humans doing important work. It didn’t make sense then and it doesn’t make sense now. The logic of layoffs is rarely visible from the inside.&lt;/p&gt;
&lt;p&gt;The tech industry swings wildly between hiring binges and brutal layoffs. Companies staff up when they want to impress investors with growth metrics, then slash headcount when those same investors demand profitability. It’s a cycle that serves shareholders, not the people doing the actual work. And navigating this gets harder, not easier, as you advance in your career—the financial stakes rise as you take on mortgages, family responsibilities, and all the obligations that come with building a life.&lt;/p&gt;
&lt;p&gt;So how do I deal with this reality? I accept it, and I prepare.&lt;/p&gt;
&lt;h2 id=&quot;nothing-is-guaranteed%2C-so-always-be-preparing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#nothing-is-guaranteed%2C-so-always-be-preparing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Nothing is Guaranteed, So Always Be Preparing&lt;/h2&gt;
&lt;p&gt;Here’s what I told my friend, and what I try to practice myself: Nothing is guaranteed, so it’s important for each of us to consider our strengths and weaknesses and to prepare.&lt;/p&gt;
&lt;p&gt;That preparation isn’t about living in fear. It’s about building the kind of career resilience that creates opportunities even when your current job disappears. And critically, it’s about being careful not to tie your identity to the company’s decisions. Your mental health depends on recognizing that business decisions you can’t control don’t define your worth. You can control your skills, your relationships, and your preparation—so that’s where to focus your energy.&lt;/p&gt;
&lt;h3 id=&quot;build-relationships-inside-and-outside-your-company&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#build-relationships-inside-and-outside-your-company&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Build Relationships Inside and Outside Your Company&lt;/h3&gt;
&lt;p&gt;The most important preparation isn’t technical—it’s relational. I wouldn’t be at GitHub if I hadn’t met &lt;a href=&quot;https://orderedlist.com/&quot;&gt;Steve Smith&lt;/a&gt; and &lt;a href=&quot;https://johnnunemaker.com/&quot;&gt;John Nunemaker&lt;/a&gt; at a small meetup at Notre Dame back in 2007. We kept in touch, built a friendship over three years, and in 2010 &lt;a href=&quot;https://jonmagic.com/posts/hey-mom-i-got-a-job/&quot;&gt;they offered me a job&lt;/a&gt; at Ordered List. A year later, when &lt;a href=&quot;https://jonmagic.com/posts/githubber/&quot;&gt;GitHub acquired Ordered List&lt;/a&gt;, that entire relationship network came with me.&lt;/p&gt;
&lt;p&gt;One conversation at one meetup created a cascade of opportunities that shaped my entire career. But here’s the thing—I wasn’t networking in the transactional sense. I was genuinely interested in what they were building. I showed up consistently. I contributed where I could. The relationship was real long before it became professionally valuable.&lt;/p&gt;
&lt;p&gt;Network with intention, but with authenticity. Get off your butt and go to meetups even when you don’t feel like it. Reach out to people whose work you admire. Contribute to projects and communities you care about. These relationships compound over time in ways you can’t predict.&lt;/p&gt;
&lt;h3 id=&quot;interview-every-1-4-years%2C-even-when-you%E2%80%99re-happy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#interview-every-1-4-years%2C-even-when-you%E2%80%99re-happy&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Interview Every 1-4 Years, Even When You’re Happy&lt;/h3&gt;
&lt;p&gt;This one is uncomfortable to hear, but it’s critical. Go on interviews even when you don’t need a job.&lt;/p&gt;
&lt;p&gt;I’ve done this every 3-4 years since joining GitHub. Not necessarily because I was looking to leave, but because interview skills atrophy without use. I’ve never been a naturally strong interviewer, so it’s been important for me to exercise that muscle and get over my fears and insecurities.&lt;/p&gt;
&lt;p&gt;Here’s the tactical part most people won’t tell you. Your first few interviews when you start interviewing again should never be with the company you want to work for. Those are practice. Those are to shake the rust off. Learn from those early interviews on companies that are further down your list.&lt;/p&gt;
&lt;p&gt;I’ve failed a lot of interviews. I failed at Google. I failed at startups where the combined experience of the entire team was less than mine. I failed at companies where I was good friends with people on the team I was interviewing for, people who knew my work. Each failure taught me something. Interviewing is a skill that requires repetition, not cramming.&lt;/p&gt;
&lt;p&gt;And here’s the irony—those periodic check-ins with the market actually made me appreciate GitHub more. Seeing what else was out there helped me recognize what I had. That quick check to see if the grass was greener helped me come back each time and appreciate where I was even more.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p&gt;&lt;strong&gt;Feedback I received on this post:&lt;/strong&gt; “One thing that can accelerate this learning is paying for professional mock interviews. It’s humbling how quickly an experienced interviewer can spot your blind spots. That external feedback is worth far more than another week of solo practice.”&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;do-as-much-of-your-work-in-the-open-as-possible&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#do-as-much-of-your-work-in-the-open-as-possible&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Do As Much of Your Work in the Open as Possible&lt;/h3&gt;
&lt;p&gt;If you can’t show your work, you can’t prove your work. This has been one of my core practices for almost two decades—make things public whenever possible.&lt;/p&gt;
&lt;p&gt;Every blog post I wrote about &lt;a href=&quot;https://jonmagic.com/posts/hubot-scripts-explained/&quot;&gt;Hubot&lt;/a&gt; in &lt;a href=&quot;https://jonmagic.com/posts/hipchat-hubot-and-me/&quot;&gt;2011&lt;/a&gt; is still online, still demonstrating my technical thinking. &lt;a href=&quot;https://jonmagic.com/posts/the-history-of-speaker-deck/&quot;&gt;The Speaker Deck project&lt;/a&gt; I helped build is still in my portfolio. The conference talks I gave in &lt;a href=&quot;https://jonmagic.com/posts/my-trip-to-verona/&quot;&gt;Italy&lt;/a&gt; and elsewhere are still searchable. All of this public work has opened doors I didn’t even know existed.&lt;/p&gt;
&lt;p&gt;Your portfolio is your interview that never stops running. When I joined Ordered List, and later when GitHub acquired us, people didn’t need to guess what I could do. They could see my code, read my explanations, watch my talks. The friction of hiring me was lower because the evidence was public.&lt;/p&gt;
&lt;p&gt;Here’s the ladder I’ve seen work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Foundation&lt;/strong&gt;: Code in public repositories. Contribute to open source. Even small contributions count.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next level&lt;/strong&gt;: Start a blog. Document what you’re learning. It doesn’t have to be groundbreaking—tutorials and how-tos are incredibly valuable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level up&lt;/strong&gt;: Build a cadence of writing and sharing. Consistency matters more than perfection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If you’re brave or even if you’re not&lt;/strong&gt;: Try public speaking. Start at local meetups. Work up to conference talks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Throughout all of this&lt;/strong&gt;: Build genuine relationships. The network you create while doing public work is as valuable as the work itself.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The content you create today can help you get interviews years from now. I know because it’s happened to me.&lt;/p&gt;
&lt;h3 id=&quot;document-everything&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#document-everything&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Document Everything&lt;/h3&gt;
&lt;p&gt;This is both practical and strategic. Document your work, your decisions, your contributions. Keep a record of your accomplishments, the problems you solved, the impact you had.&lt;/p&gt;
&lt;p&gt;Why? Because when you do need to interview, you’ll have concrete examples ready. Because when performance review time comes, you won’t be trying to remember what you did six months ago. Because if your role gets eliminated, you’ll have a clear narrative of your value to share with the next employer.&lt;/p&gt;
&lt;p&gt;I keep notes on everything. Conversations, technical decisions, projects shipped. It’s my external memory and my career insurance policy.&lt;/p&gt;
&lt;h3 id=&quot;analyze-yourself&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#analyze-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Analyze Yourself&lt;/h3&gt;
&lt;p&gt;I learned the &lt;a href=&quot;https://en.wikipedia.org/wiki/SWOT_analysis&quot;&gt;SWOT analysis framework&lt;/a&gt; in college and &lt;a href=&quot;https://jonmagic.com/posts/swot-analysis/&quot;&gt;I’ve been using it ever since&lt;/a&gt;. Every few months, I sit down with pen and paper and brutally assess my Strengths, Weaknesses, Opportunities, and Threats.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;There are great alternatives to SWOT including SOAR (Strengths, Opportunities, Aspirations, Results), &lt;a href=&quot;https://en.wikipedia.org/wiki/Gap_analysis&quot;&gt;Gap Analysis&lt;/a&gt;, and &lt;a href=&quot;https://en.wikipedia.org/wiki/Balanced_scorecard&quot;&gt;Personal Balanced Scorecard&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The key is brutal honesty. You’re not sharing this with anyone, so don’t sugar-coat the weaknesses. Don’t undersell the strengths. Look for opportunities that address multiple weaknesses while building on strengths. Identify threats that could turn strengths into weaknesses.&lt;/p&gt;
&lt;p&gt;After doing this a few times, patterns emerge. You start to see where you’re vulnerable, where you need to grow, where the market is moving. This isn’t abstract self-help—it’s strategic career planning.&lt;/p&gt;
&lt;h2 id=&quot;the-long-game&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#the-long-game&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Long Game&lt;/h2&gt;
&lt;p&gt;One of the most accelerating forces in my career has been &lt;a href=&quot;https://jonmagic.com/posts/mentors/&quot;&gt;mentorship&lt;/a&gt;, both receiving it and eventually giving it.&lt;/p&gt;
&lt;p&gt;When I started at Ordered List, I paired with &lt;a href=&quot;https://opensoul.org/&quot;&gt;Brandon Keepers&lt;/a&gt; three or four days a week. He had years of programming experience and taught me how to write maintainable code, how to think through problems, how to build elegant solutions. That intensive pairing compressed years of learning into months.&lt;/p&gt;
&lt;p&gt;John mentored me on career growth and personal development through weekly meetings. We talked about goals, about challenges, about life beyond code. That external perspective helped me see patterns I couldn’t see myself.&lt;/p&gt;
&lt;p&gt;Mentorship accelerates your growth, gives you perspective from someone who’s seen more careers (including failures), holds you accountable, and expands your network. A good mentor warns you about pitfalls before you hit them.&lt;/p&gt;
&lt;p&gt;Finding mentors takes patience. The relationship with Steve and John that eventually led to my job started years before they hired me. You can’t sprint relationship building. But you can be intentional about seeking out people you respect and learning from them.&lt;/p&gt;
&lt;p&gt;And eventually, you pay it forward. Mentoring others isn’t just good karma—it deepens your own understanding and expands your network in new directions.&lt;/p&gt;
&lt;h2 id=&quot;the-reality-of-failure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#the-reality-of-failure&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Reality of Failure&lt;/h2&gt;
&lt;p&gt;I need to say this clearly. Building career security through these practices doesn’t mean you won’t fail. You will. I have.&lt;/p&gt;
&lt;p&gt;I’ve failed interviews at companies I desperately wanted to join. I’ve given talks that landed flat. I’ve written a lot of code that got rejected. I’ve built relationships that didn’t lead anywhere personally or professionally.&lt;/p&gt;
&lt;p&gt;But each failure was data. Each one taught me something. The key is to not let failure discourage you from continuing to build these muscles.&lt;/p&gt;
&lt;p&gt;Interview prep isn’t something most people can do in a few days or even weeks. It takes repetition to build the skills and confidence to pass technical interviews. Portfolio building isn’t a weekend project. Public speaking doesn’t get comfortable after one talk.&lt;/p&gt;
&lt;p&gt;This is all a long game. Start now, not when you need it.&lt;/p&gt;
&lt;h2 id=&quot;what-this-looks-like-in-practice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#what-this-looks-like-in-practice&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What This Looks Like in Practice&lt;/h2&gt;
&lt;p&gt;Let me be concrete about what “always be preparing” means:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This month:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attend one meetup or community event&lt;/li&gt;
&lt;li&gt;Write one blog post or tutorial (even a short one)&lt;/li&gt;
&lt;li&gt;Update your resume/portfolio with recent work&lt;/li&gt;
&lt;li&gt;Reach out to one person you admire&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;This quarter:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do a SWOT analysis on yourself&lt;/li&gt;
&lt;li&gt;Contribute to one open source project&lt;/li&gt;
&lt;li&gt;Have coffee with someone outside your immediate team&lt;/li&gt;
&lt;li&gt;Document your major accomplishments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;This year:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go on at least 2-3 practice interviews&lt;/li&gt;
&lt;li&gt;Invest in your interview skills (prep courses, mock interviews, or practice platforms)&lt;/li&gt;
&lt;li&gt;Give one talk (even at a small meetup)&lt;/li&gt;
&lt;li&gt;Build one public project&lt;/li&gt;
&lt;li&gt;Find or strengthen one mentoring relationship&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these are radical. None require quitting your job or working 80-hour weeks. But together, consistently practiced, they build the foundation of career security.&lt;/p&gt;
&lt;p&gt;And here’s permission you might need. If you’re overwhelmed, there’s nothing wrong with coasting short-term. Take care of yourself first. This is a marathon, not a sprint. Sometimes the smartest career move is to preserve your mental health and energy for when you really need it.&lt;/p&gt;
&lt;h2 id=&quot;the-paradox-of-preparation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#the-paradox-of-preparation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Paradox of Preparation&lt;/h2&gt;
&lt;p&gt;Here’s what I’ve learned. The best time to build job security is when you don’t need it.&lt;/p&gt;
&lt;p&gt;When you’re employed and comfortable, you can be selective about opportunities. You can practice interviewing without desperation. You can build relationships without ulterior motives. You can create public work without pressure.&lt;/p&gt;
&lt;p&gt;When layoffs come (and they will), that preparation is what saves you. Not because you have a backup plan, but because you’ve built something more valuable than job security—you’ve built career security.&lt;/p&gt;
&lt;p&gt;The relationships are already there. The portfolio already exists. The interview muscles are warm. The network already knows your work. You’re not starting from zero.&lt;/p&gt;
&lt;h2 id=&quot;back-to-my-friend&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/building-career-security-in-an-uncertain-world/#back-to-my-friend&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Back to My Friend&lt;/h2&gt;
&lt;p&gt;I can’t promise my friend that they won’t be affected by the next round of layoffs. I can’t make the next collaboration work out. I can’t make any of this fair or sensible.&lt;/p&gt;
&lt;p&gt;But I can tell them what I believe. Their value isn’t determined by any single company’s decision. Their career security comes from the skills they build, the relationships they nurture, the work they share publicly, and the preparation they do now.&lt;/p&gt;
&lt;p&gt;Nothing is guaranteed. And that’s exactly why we prepare.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Designing Collaborations, Not Just Automations</title>
    <link href="https://jonmagic.com/posts/designing-collaborations-not-just-automations/"/>
    <updated>2025-09-01T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/designing-collaborations-not-just-automations/</id>
    <content type="html">&lt;p&gt;In my last post, &lt;a href=&quot;https://jonmagic.com/posts/the-uncertain-future-of-coding-careers-and-why-im-still-hopeful/&quot;&gt;&lt;em&gt;The Uncertain Future of Coding Careers (and Why I’m Still Hopeful)&lt;/em&gt;&lt;/a&gt;, I wrote about something I’ve always found exciting as a developer: working myself out of a job so I can work myself into the next one. I don’t come from a CS background and my programming journey has always been focused on solving problems that matter to me, and that often means automating away the tedious parts of my work.&lt;/p&gt;
&lt;p&gt;The pattern has been consistent: every time I automate away repetitive work, new challenges appear upstream. And the upstream work is often more interesting, more impactful, and more human.&lt;/p&gt;
&lt;p&gt;This sequel is about how I’m seeing that play out in real time. It’s a story about reflection, the hidden purpose of seemingly tedious tasks, and the surprising power of &lt;strong&gt;designing collaborations&lt;/strong&gt;, not just automations.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/designing-collaborations-not-just-automations/jonmagic-contemplating-collaborations.webp&quot; alt=&quot;jonmagic contemplating collaborations&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;when-automation-delays-understanding&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/designing-collaborations-not-just-automations/#when-automation-delays-understanding&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; When Automation Delays Understanding&lt;/h2&gt;
&lt;p&gt;For almost a year, I tried every possible way to automate my weekly writeup to leadership (at GitHub we refer to these as snippets): pasting prompts into &lt;a href=&quot;https://github.com/copilot&quot;&gt;Copilot&lt;/a&gt;, &lt;a href=&quot;https://gist.github.com/jonmagic/83445be775791b7d3a5cc6c97641dc57&quot;&gt;building agentic workflows&lt;/a&gt;, trying out yet-to-be-released tools my coworkers are building, you name it I tried it. And every time I ran into the same problems:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The output was terrible.&lt;/strong&gt; It was verbose, inconsistent, or just plain wrong. I spent almost as much time fixing the results as I would have spent writing them myself.&lt;/p&gt;
&lt;p&gt;But more importantly, &lt;strong&gt;I wasn’t learning anything.&lt;/strong&gt; Snippets became a chore. I wasn’t reflecting, I wasn’t seeing patterns in my work, I wasn’t building understanding of what mattered. It was just another TPS report—faster busywork, not better outcomes.&lt;/p&gt;
&lt;p&gt;Here’s what took me too long to realize: writing snippets wasn’t just about informing leadership. The act of reflection—forcing myself to review the week, identify what worked, process what I learned—was building understanding in my own mind. When I automated that away, I lost something valuable: the cognitive work that made me better at my job.&lt;/p&gt;
&lt;p&gt;This applies beyond snippets. Code reviews aren’t just about catching bugs—they’re about building shared understanding of the codebase. Documentation isn’t just about recording information—it’s about clarifying your own thinking. Even debugging isn’t just about fixing problems—it’s about building mental models of how systems work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Not all tasks exist to produce an output. Some exist to build understanding.&lt;/strong&gt; Automating those defeats the whole purpose.&lt;/p&gt;
&lt;h2 id=&quot;the-breakthrough%3A-preserve-learning%2C-reduce-grunt-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/designing-collaborations-not-just-automations/#the-breakthrough%3A-preserve-learning%2C-reduce-grunt-work&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Breakthrough: Preserve Learning, Reduce Grunt Work&lt;/h2&gt;
&lt;p&gt;Two things shifted my approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A self-reflection habit.&lt;/strong&gt; In my weekly “how I work” review, I noticed my best outcomes always came from collaboration—pairing with teammates, debating with peers, even bouncing ideas off Copilot. Collaboration, human or AI, was where the wins came from.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Discovering VS Code Chat Modes.&lt;/strong&gt; &lt;a href=&quot;https://code.visualstudio.com/docs/copilot/customization/custom-chat-modes&quot;&gt;Chat Modes&lt;/a&gt; gave me a way to design a lightweight, &lt;em&gt;context-specific collaborator&lt;/em&gt; in seconds. Instead of trying to build a &lt;a href=&quot;https://gist.github.com/jonmagic/83445be775791b7d3a5cc6c97641dc57&quot;&gt;complex multi-step agentic workflow&lt;/a&gt;, I could create an AI partner with a few paragraphs of instructions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key question became: &lt;strong&gt;“What am I supposed to learn from doing this?”&lt;/strong&gt; If the answer was “nothing,” automate away. If the answer was meaningful, design a collaboration that preserves the learning while reducing the grunt work.&lt;/p&gt;
&lt;p&gt;The result was my &lt;a href=&quot;https://gist.github.com/jonmagic/bdb9ce0d706ed31c427cd1c13e2e285a&quot;&gt;&lt;strong&gt;Snippets Interviewer Chat Mode&lt;/strong&gt;&lt;/a&gt;. Instead of only collecting context and generating near final output in one go, it asks me questions, checks sources, and lets me edit and interject. Most importantly, &lt;strong&gt;it helps me think&lt;/strong&gt; about what I did that week by turning it into a conversation.&lt;/p&gt;
&lt;p&gt;When I automated the task I regained 30-45 minutes of time but &lt;strong&gt;the meaning disappeared&lt;/strong&gt;. When I designed a collaboration, &lt;strong&gt;both efficiency and understanding remained&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-this-matters-beyond-individual-tasks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/designing-collaborations-not-just-automations/#why-this-matters-beyond-individual-tasks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Why This Matters Beyond Individual Tasks&lt;/h2&gt;
&lt;p&gt;The future of coding careers isn’t about doing tasks faster—it’s about &lt;strong&gt;designing better collaborations&lt;/strong&gt; that preserve what humans need while eliminating what we don’t.&lt;/p&gt;
&lt;p&gt;I’ve been seeing this pattern emerge:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Automation replaces execution.&lt;/strong&gt; Once we know exactly what needs doing, machines can do it faster and cheaper.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaboration enhances exploration and understanding.&lt;/strong&gt; When problems are ambiguous, when we need to learn, when we don’t even know what questions to ask yet, collaboration is where value is created.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This insight is a fundamental career principle. The more you move upstream into framing, guiding, and curating—the work that builds understanding—the less replaceable you become.&lt;/p&gt;
&lt;p&gt;And it scales beyond individual work. I’ve started creating Chat Modes for my team, like &lt;a href=&quot;https://gist.github.com/jonmagic/357ca10264ac198c95d68a0203c6b1f4&quot;&gt;this one that helps us upgrade project documentation&lt;/a&gt;. It turns a solo documentation task into a collaborative process where the improved docs help new teammates onboard faster and old teammates reload context with less effort. As I wrote in &lt;a href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/&quot;&gt;Context Rules Everything Around Me&lt;/a&gt;, context creates the foundation for more effective AI collaboration.&lt;/p&gt;
&lt;h2 id=&quot;what-ai-still-can%E2%80%99t-do&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/designing-collaborations-not-just-automations/#what-ai-still-can%E2%80%99t-do&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What AI Still Can’t Do&lt;/h2&gt;
&lt;p&gt;In conversations with friends (and with ChatGPT itself, ironically), I keep coming back to a nagging question: can we ever teach machines to truly explore? To intuit? To decide what’s worth understanding?&lt;/p&gt;
&lt;p&gt;Right now, the answer is no. LLMs are incredible at predicting what comes next, but not at deciding what &lt;em&gt;ought&lt;/em&gt; to come next. They don’t have goals. They don’t want anything. They don’t care.&lt;/p&gt;
&lt;p&gt;That means exploration, venturing into the unknown, choosing what’s worth solving, building understanding through reflection—that’s still ours. And that’s good news, because exploration and understanding are the most rewarding parts of the job.&lt;/p&gt;
&lt;p&gt;My snippets Chat Mode is a perfect example. The AI can search, summarize, and draft. But only I can decide which risks matter, which collaborations deserve a shoutout, which themes are worth elevating. That’s exploration. That’s understanding. That’s me.&lt;/p&gt;
&lt;h2 id=&quot;climbing-the-abstraction-ladder&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/designing-collaborations-not-just-automations/#climbing-the-abstraction-ladder&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Climbing the Abstraction Ladder&lt;/h2&gt;
&lt;p&gt;I’m thinking about this as an abstraction ladder where each rung preserves human understanding while eliminating mechanical work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A generation ago, debugging memory management was a big part of coding.&lt;/li&gt;
&lt;li&gt;Then we moved up to writing applications without worrying about memory.&lt;/li&gt;
&lt;li&gt;Now we’re moving up again: coding with AI pair programmers that handle boilerplate, syntax, even architecture patterns.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your career is tied to a specific rung, the ladder can feel scary. But if your career is tied to &lt;em&gt;climbing the ladder itself&lt;/em&gt;—to curiosity, adaptability, and upstream thinking—you’re better positioned for whatever comes next.&lt;/p&gt;
&lt;p&gt;The skill that endures isn’t “knowing X language” or “mastering Y framework.” It’s: &lt;strong&gt;designing collaborations that preserve understanding while eliminating busywork.&lt;/strong&gt; Every new collaboration we design creates value that’s harder to automate away because it amplifies human insight rather than replacing it.&lt;/p&gt;
&lt;h2 id=&quot;new-metrics-of-accomplishment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/designing-collaborations-not-just-automations/#new-metrics-of-accomplishment&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; New Metrics of Accomplishment&lt;/h2&gt;
&lt;p&gt;Something unexpected happened when I redesigned snippets around collaboration: the &lt;em&gt;purpose&lt;/em&gt; of snippets changed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Before, snippets were proof of activity. A list of what I did.&lt;/li&gt;
&lt;li&gt;Now, snippets are a reflection. A mirror of what mattered, a record of collaboration, and a chance to give credit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By shifting from automation to collaboration, I didn’t just make snippets faster—I made them more meaningful. I came away not with a report, but with insights, gratitude, and perspective.&lt;/p&gt;
&lt;p&gt;I think this previews what’s ahead for all of us. As AI accelerates execution, the real measure of accomplishment won’t be “how much we did” but “how well we understood, framed, collaborated, and explored.”&lt;/p&gt;
&lt;h2 id=&quot;so-what%E2%80%99s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/designing-collaborations-not-just-automations/#so-what%E2%80%99s-next%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; So What’s Next?&lt;/h2&gt;
&lt;p&gt;If automation keeps marching forward, and it will, what kind of work should we focus on?&lt;/p&gt;
&lt;p&gt;Here’s my short list—all work that builds understanding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Framing problems&lt;/strong&gt;: defining what to solve is harder than solving it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exploring ambiguity&lt;/strong&gt;: the messy, undefined spaces where understanding emerges.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Curating judgment&lt;/strong&gt;: knowing which answers are right, safe, ethical, or impactful.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Designing collaborations&lt;/strong&gt;: building processes (with humans and AIs) that preserve learning while reducing grunt work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recognizing others&lt;/strong&gt;: amplifying collaboration, giving credit, building trust.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re looking for a career compass in uncertain times, ask yourself: “What am I supposed to learn from this work?” Then design collaborations that preserve that learning.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/designing-collaborations-not-just-automations/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Conclusion&lt;/h2&gt;
&lt;p&gt;When I look back on my first experiments with automating snippets, I see the broader automation trap. I thought the goal was to make the task disappear. But when the task disappeared, so did the meaning—and the understanding it was supposed to build.&lt;/p&gt;
&lt;p&gt;The breakthrough came from reframing the question. Not “How do I automate this?” but &lt;strong&gt;“How do I design a collaboration that preserves what I need to learn while eliminating what I don’t?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That’s the bigger lesson for coding careers in the age of AI. The robots aren’t replacing us anytime soon. They’ll get smarter, they’ll remix our work, they’ll even surprise us. But the frontier of exploration, understanding, and meaningful collaboration is still ours.&lt;/p&gt;
&lt;p&gt;If you want to thrive in that future, don’t just automate—collaborate. Design partnerships that make you smarter, more reflective, and more human, not just faster.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Context Rules Everything Around Me</title>
    <link href="https://jonmagic.com/posts/context-rules-everything-around-me/"/>
    <updated>2025-07-16T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/context-rules-everything-around-me/</id>
    <content type="html">&lt;p&gt;I was drowning in meetings, losing track of decisions, and manually typing notes I never revisited. Then I found a better way—capture once, reuse everywhere with AI. In this post, I’ll show how I record and transcribe meetings, feed transcripts to large language models, and generate immediate action lists, summaries, and architecture drafts. It transformed my workflow from frantic note-taking to an effortless &lt;em&gt;meeting superpower&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I record nearly every meeting call (or use my phone’s Voice Memos for in-person).&lt;/li&gt;
&lt;li&gt;I use Zoom’s built-in transcript (or convert a recording to a transcript using a tool like &lt;a href=&quot;https://goodsnooze.gumroad.com/l/macwhisper&quot;&gt;MacWhisper&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;I run the transcript through an LLM (like &lt;a href=&quot;https://github.com/copilot&quot;&gt;GitHub Copilot&lt;/a&gt;, ChatGPT, or GoogleGemini) with a prompt to produce &lt;a href=&quot;https://github.com/jonmagic/prompts/blob/main/summarize/zoom-transcript-executive-summary.md&quot;&gt;executive summaries&lt;/a&gt;, &lt;a href=&quot;https://github.com/jonmagic/prompts/blob/main/summarize/transcript-meeting-notes.md&quot;&gt;decision logs&lt;/a&gt;, or &lt;a href=&quot;https://github.com/jonmagic/prompts&quot;&gt;whatever artifacts I need&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In my experience, meeting clarity shot up, and my weekly status prep time fell by about 80%.&lt;/li&gt;
&lt;li&gt;See below for the minimal reproducible “transcript→prompt→artifact” stack you can try this weekend.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;too-many-meetings%2C-too-little-clarity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#too-many-meetings%2C-too-little-clarity&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Too Many Meetings, Too Little Clarity&lt;/h2&gt;
&lt;p&gt;Late last year, I moved into a principal engineer role at GitHub, and my meeting load tripled almost overnight. I was juggling dozens of syncs, architecture reviews, async updates, and 1:1s every week. I’d leave a call with a few scribbled bullet points, but promptly forget half of the decisions by the next day. The bigger my scope became, the less my scattered note-taking kept me afloat.&lt;/p&gt;
&lt;p&gt;I realized that if I wanted to stay on top of critical decisions—let alone communicate them to peers and leadership—I needed a better system. Enter full transcripts. Once I started capturing entire conversations verbatim, it finally “clicked” that I could feed this raw context into AI to produce highlights and next steps. The difference was night and day.&lt;/p&gt;
&lt;h2 id=&quot;why-transcripts%3F-the-breakthrough&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#why-transcripts%3F-the-breakthrough&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Why Transcripts? The Breakthrough&lt;/h2&gt;
&lt;p&gt;I initially tried built-in “auto-summaries” from meeting software, but they were half-baked or missed nuance because the prompts sucked and they lacked good speaker attributions. Then I discovered the Zoom accessibility transcript option on calls: a text feed with speaker labels that I could save manually. Suddenly, I had an accurate record of “who said what,” ready to pipe into an LLM. This overcame the usual “notes are incomplete” feeling and let me be fully present in meetings rather than trying to type everything I heard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/context-rules-everything-around-me/zoom-transcript.gif&quot; alt=&quot;zoom transcript&quot; /&gt;&lt;/p&gt;
&lt;p&gt;For in-person offsites, I used my phone’s Voice Memos to capture audio. I’d import these recordings into the MacWhisper app, which automatically transcribed and even attempted speaker detection. Although I’d sometimes need to tag speakers manually, the payoff was huge: every voice or contribution or subtle nuance was preserved.&lt;/p&gt;
&lt;p&gt;With these transcripts, a quick AI pass yielded exactly the details I needed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A bullet-pointed to-do list with owners.&lt;/li&gt;
&lt;li&gt;A short summary for my manager’s weekly update.&lt;/li&gt;
&lt;li&gt;A “what we decided” snippet for reference in a follow-up doc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before transcripts, I’d scramble to reconstruct these details by memory or rummage through half-finished notes. Now it’s one prompt away.&lt;/p&gt;
&lt;h2 id=&quot;proof%3A-fewer-%E2%80%9Cdid-we-decide-that%3F%E2%80%9D-moments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#proof%3A-fewer-%E2%80%9Cdid-we-decide-that%3F%E2%80%9D-moments&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Proof: Fewer “Did We Decide That?” Moments&lt;/h2&gt;
&lt;p&gt;After a few weeks of using transcripts in all my calls, I noticed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I was participating in meetings instead of just taking notes.&lt;/li&gt;
&lt;li&gt;My personal “action item capture rate” soared—I rarely missed tasks assigned in a meeting.&lt;/li&gt;
&lt;li&gt;I got ~4x more context out of the same meeting time because I could always re-check the transcript.&lt;/li&gt;
&lt;li&gt;My writing speed for proposals and status updates skyrocketed, saving me up to 80% of the typical prep time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Best of all, the entire team benefited. Fewer “Wait, I thought we agreed on something else” rewinds. Less chat message churn. I even started copying my executive summaries to meeting participants within seconds of a call being done, which drastically reduced random pings for clarifications.&lt;/p&gt;
&lt;p&gt;One anecdote stands out: during a three day offsite, I recorded 24 hours of brainstorming with Voice Memos, then fed them into a speech-to-text model. I posted a daily summary to keep everyone aligned. After the offsite, I produced a single, cohesive doc capturing all decisions, complete with quotes and proposals. That doc ended up steering part of our next quarter’s roadmap—something that wouldn’t have been possible if we’d relied on my scribbles alone.&lt;/p&gt;
&lt;p&gt;Some testimonials from folks who have adopted my workflows and prompts:&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p&gt;This is fantastic @jonmagic - the quality of the executive summary is suprisingly high! Going to use the heck out of this 🙇🏼&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p&gt;This is soooooo good. I’m going to have to play with this. I’ve also started to move much faster and by the end of the week, I will reflect on discussions I’ve had and not remember who they were with “Where did I hear this? Didn’t they say…?” Thank you @jonmagic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;markdown-alert markdown-alert-tip&quot;&gt;&lt;p&gt;h/t to @jonmagic, I’ve fully bought into using transcripts and AI summaries for meetings. While they’re not perfect and can hallucinate, they let me stay present instead of taking notes.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;the-minimal-reproducible-stack&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#the-minimal-reproducible-stack&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Minimal Reproducible Stack&lt;/h2&gt;
&lt;p&gt;Below is the core technology and workflow I suggest trying. It’s easy to set up on a weekend, and you’ll see immediate results.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Capture&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use Zoom or Teams recordings, making sure you enable transcripts (see gif above).&lt;/li&gt;
&lt;li&gt;For in-person: use your phone’s Voice Memos or any handheld recorder.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;markdown-alert markdown-alert-important&quot;&gt;&lt;p&gt;Get into the habit of hitting that Transcript or Record button as soon as you join a meeting and for Zoom &lt;a href=&quot;https://gist.github.com/jonmagic/a9ebeb20d7cdf94923533e0f59ad188e&quot;&gt;use an AppleScript like this&lt;/a&gt; to ensure the &lt;strong&gt;Save transcript&lt;/strong&gt; button is clicked frequently so that you don’t lose any of the transcript before the call ends.&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Transcribe&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Skip this step if you were able to get a transcript during the capture phase.&lt;/li&gt;
&lt;li&gt;For voice recordings Voice Memos is great and will generate a transcription for you if the recording isn’t too long.&lt;/li&gt;
&lt;li&gt;If you prefer a desktop app, tools like &lt;a href=&quot;https://goodsnooze.gumroad.com/l/macwhisper&quot;&gt;MacWhisper.cpp&lt;/a&gt; add speaker detection automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Feed your transcript into an LLM along with the processing instructions (aka a prompt). &lt;a href=&quot;https://github.com/copilot&quot;&gt;GitHub Copilot&lt;/a&gt; is an excellent LLM and free (or inexpensive depending on your volume).&lt;/li&gt;
&lt;li&gt;That prompt might produce an “executive summary” or an “action item list,” depending on which prompt you decide to use. See &lt;a href=&quot;https://github.com/jonmagic/prompts&quot;&gt;my repository of prompts&lt;/a&gt; for a few options to get you started.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Outputs&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Store the final summary as text or Markdown (version-control it if you want an audit trail).&lt;/li&gt;
&lt;li&gt;Share or link it to relevant tasks, tickets, or Slack for easy reference.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;I use these steps multiple times a day from meetings to capturing ideas while taking short walks. I recorded all of the context needed for an architectural decision record the other day and from there it was just a short conversation with an LLM to put it into the ADR format.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/context-rules-everything-around-me/walk-and-record.webp&quot; alt=&quot;walk and record&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;advanced-moves&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#advanced-moves&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Advanced Moves&lt;/h2&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;&lt;strong&gt;Heads-up:&lt;/strong&gt; The tools below live in my &lt;a href=&quot;https://github.com/jonmagic/scripts&quot;&gt;&lt;code&gt;jonmagic/scripts&lt;/code&gt;&lt;/a&gt; repo.
They assume you’re comfortable cloning a repository, installing and configuring the &lt;a href=&quot;https://cli.github.com/&quot;&gt;gh&lt;/a&gt; cli, installing and configuring the &lt;a href=&quot;https://llm.datasette.io/en/stable/&quot;&gt;llm&lt;/a&gt; cli, and creating shell aliases. They’re optional, but once they click, they feel like cheating.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;fetch-github-conversation-%E2%80%94-one-command-context-vacuum&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#fetch-github-conversation-%E2%80%94-one-command-context-vacuum&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; &lt;code&gt;fetch-github-conversation&lt;/code&gt; — one-command context vacuum&lt;/h3&gt;
&lt;p&gt;Pull an entire Issue, Pull Request, or Discussion thread (comments + diffs) to STDOUT, ready for your favorite prompt.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;fgc&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token environment constant&quot;&gt;$HOME&lt;/span&gt;/scripts/fetch-github-conversation&quot;&lt;/span&gt;

fgc https://github.com/org/repo/issues/123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Why it matters&lt;/em&gt; – Grabbing the full conversation (including all comments) lets the LLM reason with complete history, producing tighter summaries and reducing “what happened earlier?” churn.&lt;/p&gt;
&lt;h3 id=&quot;prepare-commit-%E2%80%94-ai-drafted-commit-messages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#prepare-commit-%E2%80%94-ai-drafted-commit-messages&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; &lt;code&gt;prepare-commit&lt;/code&gt; — AI-drafted commit messages&lt;/h3&gt;
&lt;p&gt;An interactive script for generating a git commit commit of your staged changes using the &lt;a href=&quot;https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716&quot;&gt;semantic commit message guidelines&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;commit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;~/code/jonmagic/scripts/bin/prepare-commit --commit-message-prompt-path ~/code/jonmagic/prompts/generate/commit-message.md&#39;&lt;/span&gt;

commit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Why it matters&lt;/em&gt; – You get crisp, context-rich commit messages without the mental tax of writing them from scratch—perfect when you’re shipping ten tiny PRs a day.&lt;/p&gt;
&lt;h3 id=&quot;github-conversations-research-agent-%E2%80%94-deep-dive%2C-cite-everything-analysis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#github-conversations-research-agent-%E2%80%94-deep-dive%2C-cite-everything-analysis&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; &lt;code&gt;github-conversations-research-agent&lt;/code&gt; — deep-dive, cite-everything analysis&lt;/h3&gt;
&lt;p&gt;Full tutorial coming soon but in the meantime if you’re curious to see an advanced agent and semantic RAG setup at work to thoroughly answer questions that require multi-turn research &lt;a href=&quot;https://gist.github.com/jonmagic/552a6df70428775c221831f2a95063bc&quot;&gt;check out this gist&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;privacy-%26-consent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#privacy-%26-consent&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Privacy &amp;amp; Consent&lt;/h2&gt;
&lt;p&gt;Always check local rules and company policy before recording. In some regions, it’s mandatory to disclose or request consent from all participants. Data security is crucial: if transcripts contain sensitive or personal information, encrypt them at rest and redact as needed before sending them to cloud-based LLMs. In short: be transparent, and protect confidentiality.&lt;/p&gt;
&lt;h2 id=&quot;accessibility-%26-inclusivity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#accessibility-%26-inclusivity&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Accessibility &amp;amp; Inclusivity&lt;/h2&gt;
&lt;p&gt;This isn’t just about saving you time. it’s about ensuring every voice is amplified. Transcripts help teammates who are Deaf, communicate differently, or absorb information best via text. They also bridge gaps across remote, asynchronous, and time‑zone‑spread teams. making sure no one is left out.&lt;/p&gt;
&lt;h2 id=&quot;c.r.e.a.m.-%E2%80%94-context-rules-everything-around-me&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#c.r.e.a.m.-%E2%80%94-context-rules-everything-around-me&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; C.R.E.A.M. — Context Rules Everything Around Me&lt;/h2&gt;
&lt;p&gt;In the &#39;90s, Wu‑Tang Clan rapped &lt;a href=&quot;https://www.youtube.com/watch?v=PBwAxmrE194&quot;&gt;Cash Rules Everything Around Me&lt;/a&gt;. At early GitHub, &lt;strong&gt;C.R.E.A.M.&lt;/strong&gt; was a north star for open financial ops. In 2024, my own C.R.E.A.M. stands for: &lt;strong&gt;Context Rules Everything Around Me&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Where do you go from here? Try capturing one meeting this week and feeding the transcript to your favorite LLM. If you’re already doing that, level up with advanced prompts or a record and transcribe process at an offsite. Let me know how it goes.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/context-rules-everything-around-me/#feedback&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Feedback&lt;/h2&gt;
&lt;p&gt;I would love to hear from you: &lt;a href=&quot;https://github.com/jonmagic/jonmagic.com/discussions/8&quot;&gt;discussions/8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for your time 🙏&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Farewell RailsConf and Thank You For Everything</title>
    <link href="https://jonmagic.com/posts/farewell-railsconf-and-thank-you-for-everything/"/>
    <updated>2025-07-07T23:59:59Z</updated>
    <id>https://jonmagic.com/posts/farewell-railsconf-and-thank-you-for-everything/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;2006, Chicago.&lt;/strong&gt; Nearly everyone at the first RailsConf tapped away on a MacBook, except about fifty rebels. My friend &lt;a href=&quot;http://mintchaos.com/&quot;&gt;Christian Metts&lt;/a&gt;, who had &lt;a href=&quot;https://jonmagic.com/posts/ten-years-a-software-engineer/&quot;&gt;introduced me to Rails&lt;/a&gt;, and I printed &lt;a href=&quot;https://jonmagic.com/images/posts/farewell-railsconf-and-thank-you-for-everything/certificate.webp&quot;&gt;&lt;em&gt;Certificates of Nonconformity&lt;/em&gt;&lt;/a&gt;, forged Bill Gates’ and Linus Torvalds’ signatures, and handed them to the non-MacBook crowd &lt;a href=&quot;https://www.flickr.com/photos/mintchaos/albums/72157594176520552/&quot;&gt;while Christian snapped photos of each proud hold-out&lt;/a&gt;, including the elusive &lt;em&gt;why the lucky stiff&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/farewell-railsconf-and-thank-you-for-everything/why-the-lucky-stiff.webp&quot; alt=&quot;why the lucky stiff holding a certificate of nonconformity&quot; /&gt;&lt;/p&gt;
&lt;p&gt;That playful moment, the community, and the shared curiosity, set the tone for everything that followed.&lt;/p&gt;
&lt;h2 id=&quot;finding-rails-%26-finding-my-people&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/farewell-railsconf-and-thank-you-for-everything/#finding-rails-%26-finding-my-people&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Finding Rails &amp;amp; Finding My People&lt;/h2&gt;
&lt;p&gt;Like many, using Rails was &lt;a href=&quot;https://jonmagic.com/posts/ten-years-a-software-engineer/&quot;&gt;the forcing function for me to learn Ruby&lt;/a&gt; (with help from &lt;a href=&quot;https://poignant.guide/&quot;&gt;why’s poignant guide to Ruby&lt;/a&gt; 🙏), and that first conference pushed me deeper. Soon after, I drove to a Ruby meetup at Notre Dame and met &lt;a href=&quot;https://johnnunemaker.com/&quot;&gt;John Nunemaker&lt;/a&gt; and &lt;a href=&quot;https://orderedlist.com/&quot;&gt;Steve Smith&lt;/a&gt;. One afternoon over beers at Fiddler’s Hearth in South Bend, they vented about SlideShare’s terrible user experience. I opened my terminal, installed ImageMagick, and hacked together a PDF-to-image converter on the spot. That bar-top prototype grew into &lt;a href=&quot;https://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; and my first &lt;strong&gt;RubyGem&lt;/strong&gt;, &lt;a href=&quot;https://jonmagic.com/posts/grim/&quot;&gt;Grim&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;building-businesses-on-rails&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/farewell-railsconf-and-thank-you-for-everything/#building-businesses-on-rails&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Building Businesses on Rails&lt;/h2&gt;
&lt;p&gt;In December 2010 I became OrderedList’s first full-time developer, joining Steve, John, and later &lt;a href=&quot;https://opensoul.org/&quot;&gt;Brandon Keepers&lt;/a&gt; and &lt;a href=&quot;https://madebygraham.com/&quot;&gt;Matt Graham&lt;/a&gt;. We iterated on their first product Harmony, launched Speaker Deck to the public, and shipped &lt;a href=&quot;http://gaug.es/&quot;&gt;Gaug.es&lt;/a&gt;, a Rails-based analytics tool born from our dislike of Google Analytics. Consulting gigs on products like &lt;em&gt;Words With Friends&lt;/em&gt; paid the bills.&lt;/p&gt;
&lt;p&gt;Through meetups and conferences our team met the GitHub co-founders and early employees such as &lt;a href=&quot;https://adaptivepatchwork.com/&quot;&gt;Tim Clem&lt;/a&gt; and &lt;a href=&quot;https://zachholman.com/&quot;&gt;Zach Holman&lt;/a&gt;. In the fall of 2011 GitHub invited us to join as their first &lt;strong&gt;acqui-hire&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/farewell-railsconf-and-thank-you-for-everything/orderedlist-joins-github.webp&quot; alt=&quot;OrderedList joins GitHub&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-github-career&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/farewell-railsconf-and-thank-you-for-everything/#a-github-career&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; A GitHub Career&lt;/h2&gt;
&lt;p&gt;After our acquihire in late 2011, I worked my way through nearly every department at GitHub building our support software (a Rails app called Halp), integrating our business systems with the GitHub monolith, building tools for our customers to migrate between GitHub on-prem instances and our hosted instance, shipping 2fa enforcement features for our business customers, and finally landing in the Security department where I’ve been for nearly 9 years now.&lt;/p&gt;
&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p&gt;Brandon, John, and I were among GitHub’s earliest users, with &lt;strong&gt;IDs #173, #235, and #623&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;In Security I’ve built multiple Rails applications but only one of them is still in heavy use. Funny enough it’s a stream processing application where the Rails MVC has been swapped out with Consumer, Enrichment, and Detection modules to handle the majority of our automated abuse detection and remediation flows processing billions of events per day.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/farewell-railsconf-and-thank-you-for-everything/building-hamzo-at-an-offsite.webp&quot; alt=&quot;building hamzo at an offsite&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I still work on the GitHub Rails monolith from time to time, but new Rails apps are rare for me now, and I miss it. There’s nothing like spinning up a Rails app from scratch and going from zero to usable in minutes. Rails made it simple to focus on the business problem and get something up and running quickly with the tradeoff that &lt;a href=&quot;https://github.com/jonmagic/arca&quot;&gt;scaling later may come with some headaches&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-last-railsconf&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/farewell-railsconf-and-thank-you-for-everything/#the-last-railsconf&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Last RailsConf&lt;/h2&gt;
&lt;p&gt;This week in Philadelphia they are holding the &lt;strong&gt;last RailsConf&lt;/strong&gt;, concluding nearly 20 years of tradition. Ruby Central is &lt;a href=&quot;https://rubycentral.org/news/announcing-railsconf-2025-and-a-new-chapter-for-ruby-central-events/&quot;&gt;shifting focus to RubyConf and stewardship of RubyGems and Bundler&lt;/a&gt;, while The Rails Foundation steps into Rails stewardship via &lt;a href=&quot;https://rubyonrails.org/world/&quot;&gt;Rails World&lt;/a&gt;, which &lt;a href=&quot;https://www.linkedin.com/posts/david-heinemeier-hansson-374b18221_the-first-rails-world-sold-out-in-45-minutes-activity-7328326453291307008--DPg/&quot;&gt;sold out Toronto in seconds&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DHH&lt;/strong&gt;, creator of Rails, &lt;a href=&quot;https://world.hey.com/dhh/the-last-railsconf-c6188593&quot;&gt;shares the sentiment&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Few numbers exemplified the early growth… we bootstrapped something from nothing, turned it into an epoch‑defining event… RailsConf 2025 will be the last RailsConf… I raise my glass to the final RailsConf.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While I haven’t been deeply involved in the Rails community recently, as I prepared this post I learned how Rails World and RubyConf are shaping Rails’ future, and I’m hopeful for the aspiring or seasoned software developer that finds Rails and it changes their life like it did mine.&lt;/p&gt;
&lt;h2 id=&quot;a-thankful-reflection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/farewell-railsconf-and-thank-you-for-everything/#a-thankful-reflection&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; A Thankful Reflection&lt;/h2&gt;
&lt;p&gt;RailsConf gave me identity, community, and confidence. But more than anything, it connected me with incredible people, from the early Rails pioneers I met at conferences to the teammates who became lifelong friends, from mentors who shaped my thinking to fellow developers who challenged me to grow. The names and faces have accumulated over nearly two decades, each person adding something meaningful to my journey. The Rails community has always understood that great software comes from great people working together.&lt;/p&gt;
&lt;p&gt;So this last RailsConf isn’t a swan song, it’s a celebration. My professional software development journey started here, and I’m deeply grateful. Here’s to the Rails way: convention over configuration, developer productivity, and a culture of collaboration. Thank you, RailsConf, and thank you, Rails community.&lt;/p&gt;
&lt;h2 id=&quot;one-more-thing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/farewell-railsconf-and-thank-you-for-everything/#one-more-thing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; One More Thing&lt;/h2&gt;
&lt;p&gt;I haven’t created a Rails app recently but I still write a lot of Ruby and share most of it as open source including &lt;a href=&quot;https://github.com/jonmagic/pocketflow-ruby&quot;&gt;my port of pocketflow to Ruby&lt;/a&gt;, &lt;a href=&quot;https://github.com/jonmagic/scripts&quot;&gt;my scripts project for AI workflows&lt;/a&gt;, and a few of &lt;a href=&quot;https://jonmagic.com/projects/&quot;&gt;my other projects&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/farewell-railsconf-and-thank-you-for-everything/#feedback&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Feedback&lt;/h2&gt;
&lt;p&gt;Feedback is welcome: &lt;a href=&quot;https://github.com/jonmagic/jonmagic.com/discussions/7&quot;&gt;discussions/7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for your time 🙏&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Adding client-side semantic search to jonmagic.com</title>
    <link href="https://jonmagic.com/posts/adding-client-side-semantic-search-to-jonmagic-com/"/>
    <updated>2025-07-03T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/adding-client-side-semantic-search-to-jonmagic-com/</id>
    <content type="html">&lt;p&gt;I recently rebuilt &lt;a href=&quot;http://jonmagic.com/&quot;&gt;jonmagic.com&lt;/a&gt; from the ground up with help from &lt;a href=&quot;https://github.com/features/copilot&quot;&gt;GitHub Copilot&lt;/a&gt;, transforming it from a boring &lt;a href=&quot;https://jonmagic.com/about/&quot;&gt;about page&lt;/a&gt; into a real blog and migrating over 100 posts from my old blog. After adding this much content, I wanted a way to make it searchable, but using &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;eleventy&lt;/a&gt; on &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; meant there was no backend to rely on.&lt;/p&gt;
&lt;p&gt;Most of my projects these days involve building AI-powered features, so I started to wonder if it was possible to add semantic search that runs entirely in the browser, even on a static site? Turns out &lt;a href=&quot;https://github.com/jonmagic/jonmagic.com/pull/5&quot;&gt;it is&lt;/a&gt; and with a little help from ChatGPT and Copilot I had it up and running in an hour.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; width=&quot;640&quot; poster=&quot;https://jonmagic.com/images/search-demo.png&quot;&gt;
    &lt;source src=&quot;https://jonmagic.com/images/posts/adding-client-side-semantic-search-to-jonmagic-com/search-demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Sorry, your browser doesn&#39;t support embedded videos.
  &lt;/video&gt;
  &lt;figcaption&gt;
    &lt;strong&gt;Video Demo:&lt;/strong&gt; Semantic search returning posts that match concepts, not just keywords.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The entire semantic search (including the model) runs on your device, inside the browser, using precomputed post embeddings. No server required!&lt;/p&gt;
&lt;p&gt;Try it yourself: &lt;a href=&quot;https://jonmagic.com/search/&quot;&gt;Search jonmagic.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Later I found out about &lt;a href=&quot;https://pagefind.app/&quot;&gt;https://pagefind.app/&lt;/a&gt; and did briefly consider it but afaict it doesn’t support semantic search and my site only has a little over 100 blog posts so I’m very happy with the solution I landed on.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/adding-client-side-semantic-search-to-jonmagic-com/#how-it-works&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; How It Works&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. Embedding posts during build.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At build time, I use &lt;a href=&quot;https://xenova.github.io/transformers.js/&quot;&gt;@xenova/transformers&lt;/a&gt; to generate a vector embedding for each post. This happens in the build script:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/_build/indexVectors.js (excerpt)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tensor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;extractor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;textToEmbed&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;pooling&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;mean&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;normalize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
updated&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;full&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tensor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These go into a static &lt;code&gt;vectors.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Embedding queries in the browser.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On the search page, as you type, your query text is embedded &lt;strong&gt;client-side&lt;/strong&gt; using the &lt;em&gt;same&lt;/em&gt; model (MiniLM-L6-v2). That means no server round-trips, and your queries are never sent anywhere.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/js/embedQuery.js (excerpt)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; pipeline &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2/dist/transformers.min.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; extractor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;feature-extraction&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Xenova/all-MiniLM-L6-v2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;embedQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tensor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;extractor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;pooling&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;mean&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;normalize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tensor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. Finding the best matches.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The browser calculates cosine similarity between your query embedding and every post embedding. The top matches are shown, sorted by score.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/js/search.js (excerpt)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cosineSim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; dot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; normA &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; normB &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dot &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    normA &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    normB &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; dot &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;normA&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;normB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;topK&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;queryVec&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; vectorData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vectorData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;filePath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cosineSim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queryVec&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;score &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;score&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-you-can-search-for&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/adding-client-side-semantic-search-to-jonmagic-com/#what-you-can-search-for&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What You Can Search For&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Topics:&lt;/strong&gt; e.g., &lt;code&gt;&amp;quot;project management&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;learning new skills&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Questions:&lt;/strong&gt; e.g., &lt;code&gt;&amp;quot;advice for new developers&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fuzzy phrases:&lt;/strong&gt; e.g., &lt;code&gt;&amp;quot;why did I move to git?&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;being acquired at work&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You’re not limited to exact words, vector search will match &lt;em&gt;related&lt;/em&gt; posts.&lt;/p&gt;
&lt;h2 id=&quot;what%E2%80%99s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/adding-client-side-semantic-search-to-jonmagic-com/#what%E2%80%99s-next%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What’s Next?&lt;/h2&gt;
&lt;p&gt;Next I’d like to see if client-side &lt;a href=&quot;https://en.wikipedia.org/wiki/Retrieval-augmented_generation&quot;&gt;Retrieval Augmented Generation (RAG)&lt;/a&gt; is possible.  That is, not only find relevant posts, but also pass their text into a client-side LLM that can summarize or answer questions &lt;em&gt;about my own blog&lt;/em&gt;, entirely on your device.&lt;/p&gt;
&lt;p&gt;If you’re interested in following along, &lt;a href=&quot;https://jonmagic.com/feed.xml&quot;&gt;subscribe to the feed&lt;/a&gt; or check out the &lt;a href=&quot;https://jonmagic.com/search/&quot;&gt;search page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/adding-client-side-semantic-search-to-jonmagic-com/#feedback&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Feedback&lt;/h2&gt;
&lt;p&gt;Feedback is welcome: &lt;a href=&quot;https://github.com/jonmagic/jonmagic.com/discussions/6&quot;&gt;discussions/6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for your time 🙏&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Uncertain Future of Coding Careers and Why I&#39;m Still Hopeful</title>
    <link href="https://jonmagic.com/posts/the-uncertain-future-of-coding-careers-and-why-im-still-hopeful/"/>
    <updated>2025-06-27T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/the-uncertain-future-of-coding-careers-and-why-im-still-hopeful/</id>
    <content type="html">&lt;p&gt;A friend of mine, bright, driven, and relatively new to programming, asked me a heavy question the other day. “Did I make a mistake? Did I choose the right career?”&lt;/p&gt;
&lt;p&gt;The question hung in the air. It wasn’t born from a bad day or a frustrating bug. It came from a much deeper place of anxiety, one that I suspect many in our industry are feeling right now. They saw recent waves of layoffs, they read the headlines about Artificial Intelligence, and they felt the ground shifting under their feet. The promise of a stable, in-demand career in tech, which seemed like a sure thing just a few years ago, now felt fragile.&lt;/p&gt;
&lt;p&gt;“I’m so early in my career,” they said, “I worry if I’ll even have a job in a few years. It’s hard to stay motivated.”&lt;/p&gt;
&lt;p&gt;I had to be honest. I hear them. Loud and clear.&lt;/p&gt;
&lt;p&gt;I’m no expert, and my perspective is limited to my own journey, roughly 28 years in the tech world, nearly 15 of those as a full time software developer. I’ve seen a few cycles of boom and bust, but I’ll admit, this moment feels different. When I first got access to GitHub Copilot a few years ago, I had my own panic. I’m in my 40s. Was I becoming a fossil? How could I keep up?&lt;/p&gt;
&lt;p&gt;That initial fear, however, eventually gave way to something else, a fire. It was a rallying cry to push myself, to embrace my love for learning, and to continuously grow. It reinforced a mindset I’ve tried to cultivate over the years, to constantly work to make my current role obsolete, because in doing so, I’m constantly working my way into my next one.&lt;/p&gt;
&lt;p&gt;This is the sober part of the conversation, the industry has pendulums. Companies hire like mad for whatever reason, and then they overcorrect with layoffs. It’s a stressful reality. Imposter syndrome, that nagging feeling of being a fraud, doesn’t go away. I still feel it. But over time, I’ve learned to reframe it. Instead of feeling overwhelmed by all the brilliant people around me, I now feel a sense of awe and a desire to learn from them. It’s fuel.&lt;/p&gt;
&lt;p&gt;But what about the elephant in the room, AI? My friend’s biggest fear was that AI will simply do what’s expected of a more junior engineer, making their role disappear.&lt;/p&gt;
&lt;p&gt;This is where my hope for the future comes in.&lt;/p&gt;
&lt;p&gt;I don’t believe we’re heading for a world where artificial general intelligence (AGI) makes human ingenuity obsolete. Look closely at every major breakthrough, even those in AI-driven medicine. It’s still humans pointing the AI down the right paths. Human creativity is the spark.&lt;/p&gt;
&lt;p&gt;What I see is a future where AI handles the grunt work, freeing us up to focus on the truly human part of creation: the next step, the novel idea, the new invention. If we don’t have to spend five years of our early careers doing repetitive tasks, that isn’t a threat, it’s a massive opportunity. It’s an acceleration of our potential.&lt;/p&gt;
&lt;p&gt;This led me to a profound realization that now guides my work. We are all, collectively, building a giant, shared brain.&lt;/p&gt;
&lt;p&gt;Every time you write a blog post, answer a question on a forum, or push a project to GitHub, you are contributing to this massive corpus of human knowledge. The next generation of AI models will ingest that information. Your solution, your idea, your unique way of explaining something, becomes part of the shared intelligence of our species. When someone else, somewhere else, asks a question that overlaps with something you shared, they’ll be able to build on your work.&lt;/p&gt;
&lt;p&gt;We are not just leveling up ourselves when we write and share; we are leveling up all of humanity.&lt;/p&gt;
&lt;p&gt;So, how do we thrive in this new world?&lt;/p&gt;
&lt;p&gt;First, we must become masters of context. The effectiveness of AI hinges on the quality of the information we give it. I’ve started obsessively collecting my own context, transcripts, notes, ideas, with the goal of building a personal, searchable database that I can use to augment my own thinking and my interactions with AI.&lt;/p&gt;
&lt;p&gt;Second, we must learn to be shepherds, not just button-pushers. For those of us who write code, this means getting exceptionally good at describing problems and guiding AI to generate solutions. For our colleagues in non-engineering roles, it means learning to see opportunities for automation and building the AI agents to handle them. We all need to adopt a mindset of invention.&lt;/p&gt;
&lt;p&gt;Finally, we must guard against brain atrophy. We can’t let the tool do all the thinking. Use AI as an accelerator, a tireless research assistant, and a pair programmer, but never as a replacement for your own curiosity and ingenuity.&lt;/p&gt;
&lt;p&gt;So, did my friend make a mistake choosing to be a programmer?&lt;/p&gt;
&lt;p&gt;Absolutely not. The barrier to entry for creating things with software will get lower, but this doesn’t devalue the profession, it transforms it. The demand for people who can solve problems, think critically, and apply human ingenuity will be higher than ever.&lt;/p&gt;
&lt;p&gt;The future of this career isn’t about being replaced by a machine. It’s about being amplified by one. Our challenge, and our great opportunity, is to learn how to contribute to that giant, shared brain and use its power to build things we can barely even imagine today.&lt;/p&gt;
&lt;h2 id=&quot;footnotes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/the-uncertain-future-of-coding-careers-and-why-im-still-hopeful/#footnotes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Junior engineers are still essential (&lt;a href=&quot;https://www.businessinsider.com/github-ceo-hiring-junior-engineers-interns-important-2025-6&quot;&gt;businessinsider.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Copilot boosts satisfaction and productivity (&lt;a href=&quot;https://github.blog/news-insights/research/research-quantifying-github-copilots-impact-in-the-enterprise-with-accenture/&quot;&gt;github.blog&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Copilot makes devs ~55% faster (&lt;a href=&quot;https://arxiv.org/abs/2302.06590&quot;&gt;arxiv.org&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Copilot improves speed, solution quality (&lt;a href=&quot;https://arxiv.org/abs/2506.10051&quot;&gt;arxiv.org&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Copilot training data includes public GitHub repos (&lt;a href=&quot;https://linearb.io/blog/is-github-copilot-worth-it&quot;&gt;linearb.io&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Large language models trained on Stack Overflow, GitHub, Wikipedia (&lt;a href=&quot;https://arxiv.org/abs/2303.08733&quot;&gt;arxiv.org&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Layoffs in 2023 hit 262,735 (&lt;a href=&quot;https://techcrunch.com/2024/05/01/a-comprehensive-archive-of-2023-tech-layoffs/&quot;&gt;techcrunch.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Tech layoffs in 2024 (&lt;a href=&quot;https://www.fastcompany.com/91358076/tech-layoffs-list-june-2025-microsoft-google-disney-zoominfo&quot;&gt;fastcompany.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Over 62,000 layoffs already in early 2025 (&lt;a href=&quot;https://www.nerdwallet.com/article/finance/tech-layoffs&quot;&gt;nerdwallet&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/the-uncertain-future-of-coding-careers-and-why-im-still-hopeful/#feedback&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Feedback&lt;/h2&gt;
&lt;p&gt;Feedback is welcome: &lt;a href=&quot;https://github.com/jonmagic/jonmagic.com/discussions/2&quot;&gt;discussions/2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for your time 🙏&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Peer feedback</title>
    <link href="https://jonmagic.com/posts/peer-feedback/"/>
    <updated>2023-04-25T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/peer-feedback/</id>
    <content type="html">&lt;p&gt;It’s that time of year again and I’m asking for peer feedback and writing feedback for teammates and realized I’ve learned a few things about this process over the years that I think are worth sharing.&lt;/p&gt;
&lt;h2 id=&quot;asking-for-peer-feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/peer-feedback/#asking-for-peer-feedback&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Asking for peer feedback&lt;/h2&gt;
&lt;p&gt;A close teammate and friend &lt;strong&gt;@kmcq&lt;/strong&gt; gave this piece of advice recently and it really stuck and has made this review cycle at work much more straightforward and enjoyable:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One thing that I’ve found helps me write better peer reviews more efficiently for folks is for the requester to mention something that they’d like me to highlight: a project, quality, or whatever that I can speak to that adds evidence to what they’ll be writing themselves. This helps focus things and saves a lot of time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I took that idea and ran with it and when I started asking my peers for feedback I included links to things I wrote or code I shipped that they could reference.&lt;/p&gt;
&lt;p&gt;This greatly reduces the burden on the people you are asking but at the same time I don’t want to limit what they include in their feedback, so my requests went something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Would you be willing to provide me peer feedback? The feedback form has pre-defined questions but here are some potential areas from our IC expectations that I would appreciate feedback on and links to work related to those areas that I completed during this review cycle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Leadership and Communication&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Provides substantial technical leadership to help others learn and grow
&lt;ul&gt;
&lt;li&gt;example 1&lt;/li&gt;
&lt;li&gt;example 2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Technical Contributions&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Demonstrates deep knowledge of data – knows what data is needed, how to find new or missing data, connects disparate or ambiguous data
&lt;ul&gt;
&lt;li&gt;example 1&lt;/li&gt;
&lt;li&gt;example 2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Typically when I provide feedback I focus it on just one expectation or project so you could just pick one of those examples above that you feel comfortable speaking to or choose something else entirely. Critical but constructive feedback is welcome and desired. If there is something I can be doing better for you or the team please don’t hold back.&lt;/p&gt;
&lt;p&gt;I would of course be happy to give you peer feedback if I can be of service.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;writing-peer-feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/peer-feedback/#writing-peer-feedback&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Writing peer feedback&lt;/h2&gt;
&lt;p&gt;I’ve been writing peer feedback two to four times a year for up to a dozen individuals for the majority of my 11 years at GitHub. Here are a few guidelines I use today that I’ve learned over the years.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;When someone asks you for peer feedback, ask them to apply the advice above! It’s a lot easier and faster to write feedback when the range of possibilities has already been narrowed down.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Address the feedback to them and not some third party like their manager.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instead of:
“I appreciate how Rachel gathers requirements from stakeholders and delivers high impact results.”&lt;/li&gt;
&lt;li&gt;Prefer:
“&lt;strong&gt;Rachel&lt;/strong&gt;, I appreciate how you gather requirements from stakeholders and deliver high impact results.”
This feedback is for them—not their manager.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There should be no surprises when giving constructive feedback during a review cycle. I like to reinforce feedback I’ve already given during the cycle, and if possible, provide examples of how I’ve seen them improve—and encourage more of that behavior.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  
  <entry>
    <title>Year in review</title>
    <link href="https://jonmagic.com/posts/year-in-review/"/>
    <updated>2017-12-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/year-in-review/</id>
    <content type="html">&lt;p&gt;This year flew by with a couple life changing family events, several projects shipped at work, and a lot of learning.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/year-in-review/IMG_5507.jpg&quot; alt=&quot;kite&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;family&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/year-in-review/#family&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Family&lt;/h2&gt;
&lt;p&gt;We took two family trips to Florida this year to visit Natalie’s parents. The first trip was after her father found out he had cancer and the second trip was to help her mom pack up and move after he passed away. Of course these weren’t easy trips but I cherish the time we had with them.&lt;/p&gt;
&lt;p&gt;Adalyn is growing up faster than I can comprehend most days. She’s opinionated, independent, and can be sweet and then harsh in the span of a few seconds. Right now I’m trying to learn how to help her concentrate on a task or project for more than a few seconds at a time.&lt;/p&gt;
&lt;p&gt;In August Natalie and I celebrated our tenth wedding anniversary (and fifteenth year together). My mom flew in to take care of Adalyn so that Natalie and I could get away for a few days. We flew to Portland and had a great time exploring a new city kid free!&lt;/p&gt;
&lt;p&gt;The final piece of big news is that Natalie is pregnant and due in April!&lt;/p&gt;
&lt;h2 id=&quot;work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/year-in-review/#work&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Work&lt;/h2&gt;
&lt;p&gt;I can’t go into detail about most of my projects now that I’m on the security team at &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;. I still write blog posts regularly but they only get posted to a private work blog. What I can talk about here is some of the cool tech I’ve been learning and using.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/year-in-review/IMG_4301.jpg&quot; alt=&quot;team&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;react%2C-graphql%2C-and-design&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/year-in-review/#react%2C-graphql%2C-and-design&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; React, GraphQL, and design&lt;/h3&gt;
&lt;p&gt;One of my responsibilities is building workflow tools for a team of analysts. Most of these workflows are queues and the analysts have to review items in the queue as quickly as possible.&lt;/p&gt;
&lt;p&gt;We chose &lt;a href=&quot;https://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt; with &lt;a href=&quot;https://github.com/rails/webpacker&quot;&gt;webpacker&lt;/a&gt; and a &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt; frontend implemented in &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;Typescript&lt;/a&gt; that reads from a &lt;a href=&quot;http://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; API using the &lt;a href=&quot;https://www.apollographql.com/client/&quot;&gt;Apollo client&lt;/a&gt; library. We’ve been able to build super fast and information rich user interfaces with this tech stack and we’re loving it for the most part.&lt;/p&gt;
&lt;p&gt;One thing that hasn’t worked great has been combining multiple API’s into a single unified GraphQL API, specifically re-exposing the &lt;a href=&quot;https://developer.github.com/early-access/platform-roadmap/&quot;&gt;GitHub Platform&lt;/a&gt; in our apps GraphQL API. We’ve had to duplicate a lot of the objects the GitHub Platform exposes and whenever we want to expose a new object or field we have to touch half a dozen places in our codebase.&lt;/p&gt;
&lt;p&gt;Thankfully the folks over at Apollo have built &lt;a href=&quot;https://dev-blog.apollodata.com/graphql-schema-stitching-8af23354ac37&quot;&gt;a server side solution&lt;/a&gt; but it’s implemented in javascript so we’re planning on swapping out Rails in our stack for a node app. We believe &lt;a href=&quot;https://www.apollographql.com/docs/graphql-tools/schema-stitching.html&quot;&gt;schema stitching&lt;/a&gt; will have a significant impact on our development speed and maintainability.&lt;/p&gt;
&lt;p&gt;I’ve also spent a good deal of time reading about user interface design and applying that knowledge to the analyst workflows. I started by reading through &lt;a href=&quot;http://www.mit.edu/~jtidwell/common_ground.html&quot;&gt;this site from 1999 by Jenifer Tidwell&lt;/a&gt; and am now reading her book &lt;a href=&quot;http://designinginterfaces.com/&quot;&gt;Designing Interfaces: Patterns for Effective Interaction Design&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;machine-learning&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/year-in-review/#machine-learning&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Machine learning&lt;/h3&gt;
&lt;p&gt;We’ve deployed multiple models to production now and have pipelines for training, testing, tuning, and deploying new models. While I haven’t been very involved with the actual model building process I have been spending a lot of my time developing new features for us to use in our models.&lt;/p&gt;
&lt;p&gt;During model development our ML stack is &lt;a href=&quot;https://prestodb.io/&quot;&gt;Presto&lt;/a&gt;, &lt;a href=&quot;http://jupyter.org/&quot;&gt;Jupyter&lt;/a&gt;, and &lt;a href=&quot;http://scikit-learn.org/&quot;&gt;scikit-learn&lt;/a&gt;. When it’s time to put things into production we use &lt;a href=&quot;https://airflow.apache.org/&quot;&gt;Airflow&lt;/a&gt; to train and tune models on a regular schedule and then the models are deployed as microservices in our &lt;a href=&quot;https://kubernetes.io/&quot;&gt;kubernetes&lt;/a&gt; cluster.&lt;/p&gt;
&lt;h3 id=&quot;stream-processing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/year-in-review/#stream-processing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Stream processing&lt;/h3&gt;
&lt;p&gt;Over the past few months we’ve switched to publishing our signals as &lt;a href=&quot;https://developers.google.com/protocol-buffers/&quot;&gt;protobuf&lt;/a&gt; messages to &lt;a href=&quot;https://kafka.apache.org/&quot;&gt;kafka&lt;/a&gt; so that we can use any number of consumers and start experimenting with stream processing.&lt;/p&gt;
&lt;p&gt;We’re currently running two types of stream processors. The first is a Ruby app using the &lt;a href=&quot;https://github.com/zendesk/racecar&quot;&gt;Racecar gem&lt;/a&gt;. This app has let us experiment quickly with new streams and has helped us enable everyone on the team to do some basic stream processing.&lt;/p&gt;
&lt;p&gt;The second one we’ve been experimenting with is &lt;a href=&quot;https://flink.apache.org/&quot;&gt;Flink&lt;/a&gt;. It is way faster and has many more features than our simple ruby consumer app but we’re still ironing out the development process for the rest of our team as you have to write Flink apps with Java, &lt;a href=&quot;https://www.scala-lang.org/&quot;&gt;Scala&lt;/a&gt;, or &lt;a href=&quot;https://kotlinlang.org/&quot;&gt;Kotlin&lt;/a&gt;. Our initial spike with Flink was in Scala but recently we’ve been writing apps with Kotlin which I think we’ll end up preferring to Scala or Java.&lt;/p&gt;
&lt;h2 id=&quot;2017-reading-list&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/year-in-review/#2017-reading-list&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; 2017 Reading List&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.audible.com/pd/A-Man-on-the-Moon-The-Voyages-of-the-Apollo-Astronauts-Part-1-Audiobook/B016J1NMR6&quot;&gt;A Man on the Moon: The Voyages of the Apollo Astronauts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.audible.com/pd/Cyberspies-Part-1-The-Secret-History-of-Surveillance-Hacking-and-Digital-Espionage-Audiobook/B01FV0BT8U&quot;&gt;Cyberspies: The Secret History of Surveillance, Hacking, and Digital Espionage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.audible.com/pd/Into-the-Black-Part-1-The-Extraordinary-Untold-Story-of-the-First-Flight-of-the-Space-Shuttle-Columbia-and-the-Astronauts-Who-Flew-Her-Audiobook/B01DUV8W32&quot;&gt;Into the Black: The Extraordinary Untold Story of the First Flight of the Space Shuttle Columbia and the Astronauts Who Flew Her&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.audible.com/pd/Hidden-Figures-The-American-Dream-and-the-Untold-Story-of-the-Black-Women-Mathematicians-Who-Helped-Win-the-Space-Race-Audiobook/B01I28NTJU&quot;&gt;Hidden Figures: The American Dream and the Untold Story of the Black Women Mathematicians Who Helped Win the Space Race&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.audible.com/pd/The-Marvelous-Pigness-of-Pigs-Respecting-and-Caring-for-All-Gods-Creation-Audiobook/B01D3MDWEW&quot;&gt;The Marvelous Pigness of Pigs: Respecting and Caring for All God’s Creation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.audible.com/pd/Apollo-8-The-Thrilling-Story-of-the-First-Mission-to-the-Moon-Audiobook/B06Y5Q7YHS&quot;&gt;Apollo 8: The Thrilling Story of the First Mission to the Moon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.audible.com/pd/Radical-Candor-Be-a-Kick-Ass-Boss-Without-Losing-Your-Humanity-Audiobook/B01MZ6RMS4&quot;&gt;Radical Candor: Be a Kick-Ass Boss Without Losing Your Humanity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Managers-Path-Leaders-Navigating-Growth/dp/1491973897/ref=sr_1_1?ie=UTF8&amp;amp;qid=1514616553&amp;amp;sr=8-1&amp;amp;keywords=managers+path&quot;&gt;The Manager’s Path: A Guide for Tech Leaders Navigating Growth and Change&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.fullstackreact.com/&quot;&gt;Fullstack React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leanpub.com/redux-book&quot;&gt;The Complete Redux Book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://martin.zinkevich.org/rules_of_ml/rules_of_ml.pdf&quot;&gt;Rules of Machine Learning: Best Practices for ML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nostarch.com/linearalgebra&quot;&gt;The Manga Guide to Linear Algebra&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Deep-Learning-Adaptive-Computation-Machine/dp/0262035618/ref=pd_sim_14_4?_encoding=UTF8&amp;amp;pd_rd_i=0262035618&amp;amp;pd_rd_r=ZVE3307PRXX1DD691HQC&amp;amp;pd_rd_w=jeWjv&amp;amp;pd_rd_wg=Vn7CM&amp;amp;psc=1&amp;amp;refRID=ZVE3307PRXX1DD691HQC&quot;&gt;Deep Learning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Introduction-Apache-Flink-Stream-Processing/dp/1491976586&quot;&gt;Introduction to Apache Flink: Stream Processing for Real Time and Beyond&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Learning-Apache-Flink-Tanmay-Deshpande/dp/1786466228/ref=pd_lpo_sbs_14_img_0?_encoding=UTF8&amp;amp;psc=1&amp;amp;refRID=7HN2DZ597H9V24ZYE8A7&quot;&gt;Learning Apache Flink&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.safaribooksonline.com/library/view/stream-processing-with/9781491974285/&quot;&gt;Stream Processing with Apache Flink&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.safaribooksonline.com/library/view/kafka-the-definitive/9781491936153/&quot;&gt;Kafka: The Definitive Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.safaribooksonline.com/library/view/mastering-redis/9781783988181/&quot;&gt;Mastering Redis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.safaribooksonline.com/library/view/the-tao-of/9781617293146/&quot;&gt;The Tao of Microservices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;stop%2C-start%2C-continue-for-2018&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/year-in-review/#stop%2C-start%2C-continue-for-2018&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Stop, Start, Continue for 2018&lt;/h2&gt;
&lt;p&gt;I need to stop hurting my health with snacks and sugary drinks and stop working late nights and being immobile for hours on end staring at my laptop.&lt;/p&gt;
&lt;p&gt;I would like to start exercising consistently, finding medical help for ongoing pain, spending more time playing with Adalyn and hanging out with Natalie, and interviewing again.&lt;/p&gt;
&lt;p&gt;I’m going to continue studying machine learning and learning new technologies while consistently shipping at work, supporting my family and my teammates, and taking time to reflect and evolve.&lt;/p&gt;
&lt;h2 id=&quot;thank-you!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/year-in-review/#thank-you!&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Thank you!&lt;/h2&gt;
&lt;p&gt;Thank you to everyone who helped me through 2017, especially Natalie and Adalyn, my parents, and my teammates at GitHub ❤️&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/year-in-review/IMG_4359.jpg&quot; alt=&quot;adalyn birthday&quot; /&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Ten Years a Software Engineer</title>
    <link href="https://jonmagic.com/posts/ten-years-a-software-engineer/"/>
    <updated>2016-12-05T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/ten-years-a-software-engineer/</id>
    <content type="html">&lt;p&gt;Ten years ago I started programming professionally and now I’m a Senior Engineer at GitHub. This blog post begins with a retrospective and ends with what I’m looking forward to in the future.&lt;/p&gt;
&lt;h2 id=&quot;how-did-i-get-here%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/ten-years-a-software-engineer/#how-did-i-get-here%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; How did I get here?&lt;/h2&gt;
&lt;p&gt;Growing up I was always building, repairing, using, and teaching people how to use computers. With a steady stream of spare computer parts from my Uncle John and encouragement from my parents it was easy to get started and advance quickly. Most of my friends were into computers too and a couple of them got into software development but for some reason I didn’t start considering it seriously until 2006. I had done some html, css, and javascript hacking starting in the late 90’s but everything I had built up until 2006 was for myself (like my &lt;a href=&quot;http://web.archive.org/web/20041015030645/http://www.jonmagic.com/melioration/&quot;&gt;first blog&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In 2006 everything changed when customers of my company &lt;a href=&quot;https://web.archive.org/web/2012/https://web.archive.org/web/2012/https://sabretechllc.com&quot;&gt;SabreTech&lt;/a&gt; started asking if we could build software for them. The opportunity to make money was enough to get me interested and I asked my friends Christian Metts, Daniel Parker, and Joshaven Potter for advice and help. With their help we shipped a couple of projects for customers (&lt;a href=&quot;https://github.com/jonmagic/foreverrememberme&quot;&gt;foreverrememberme&lt;/a&gt; and &lt;a href=&quot;https://github.com/jonmagic/sixsigmaforms&quot;&gt;sixsigmaforms&lt;/a&gt;) and I started to catch the programming bug. That same year I attended the &lt;a href=&quot;https://www.flickr.com/photos/mintchaos/sets/72157594176520552/&quot;&gt;first RailsConf in Chicago&lt;/a&gt; and &lt;a href=&quot;https://github.com/jonmagic/optik&quot;&gt;started building software to run SabreTech’s operations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first half of 2007 we took on more projects including building a centralized billing system for a chain of tanning salons and a network and computer monitoring system with remote access infrastructure to make helping customers faster, easier, and cheaper. Programming work was still my secondary job though, my primary responsibilities were building, installing, and repairing computers and training people how to use them. At this point I was driving an average of 1000 miles per week for work and I would continue to do so for the next 3 years.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/ten-years-a-software-engineer/jon_montana_big_other.png&quot; alt=&quot;lawrence kansas&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The second half of 2007 brought major life changes including getting married and moving to Elkhart, Indiana. Shortly after moving I did a google search for “ruby south bend” and came across the SBRB group that met at the University of Notre Dame. I attended my first meeting that fall and met John Nunemaker and Steve Smith.&lt;/p&gt;
&lt;p&gt;Over the next three years I would continue doing programming projects for customers (&lt;a href=&quot;https://github.com/jonmagic/jukeman&quot;&gt;jukeman&lt;/a&gt;), for my business (&lt;a href=&quot;https://github.com/jonmagic/suitecs&quot;&gt;suitecs&lt;/a&gt;), for family (&lt;a href=&quot;https://github.com/jonmagic/globalauto&quot;&gt;globalauto&lt;/a&gt;), and one &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2011/10/03/the-history-of-speaker-deck/&quot;&gt;little side project&lt;/a&gt; with John Nunemaker and Steve Smith.&lt;/p&gt;
&lt;p&gt;That little side project &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2010/11/18/hey-mom-i-got-a-job/&quot;&gt;turned into a job offer in late 2010&lt;/a&gt; and I sold my share of SabreTech to my business partners and started working full time as a software developer at Ordered List. Brandon Keepers joined our team a few weeks after me and then Matt Graham joined a couple of months after that.&lt;/p&gt;
&lt;p&gt;Over the course of 2010 our small team &lt;a href=&quot;https://gaug.es/&quot;&gt;built a new product&lt;/a&gt; while maintaining our existing products Harmony and &lt;a href=&quot;https://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; as well as paying our salaries by consulting for companies like Zynga (we helped Zynga scale Words with Friends and helped design and build the javascript version of Words with Friends for Facebook).&lt;/p&gt;
&lt;p&gt;Along the way our friends at GitHub noticed our products and our work and in the fall of that year made an offer to acquire our small company. &lt;a href=&quot;https://github.com/blog/993-ordered-list-is-a-githubber&quot;&gt;The five of us joined GitHub on December 5th, 2011&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/ten-years-a-software-engineer/speaking.jpg&quot; alt=&quot;speaking at failcon&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Since joining GitHub I have helped serve our support team, finance team, sales team, customers (specifically GitHub Enterprise admins and Organization admins), and now our security team by designing, planning, building, and maintaining software. I’ve built and led teams along the way but my responsibilities have mostly been solving problems for my coworkers and our customers using software. Earlier this year I was promoted to Senior Engineer. This promotion was especially exciting for me as I looked back at the previous ten years and what it took to get here.&lt;/p&gt;
&lt;h2 id=&quot;what-did-i-learn-along-the-way%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/ten-years-a-software-engineer/#what-did-i-learn-along-the-way%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What did I learn along the way?&lt;/h2&gt;
&lt;p&gt;So. Many. Things.&lt;/p&gt;
&lt;p&gt;The importance of &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2011/10/20/mentors/&quot;&gt;mentors&lt;/a&gt; as accelerators to growth. Being a leader is often about &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2014/11/23/intention-vs-perception/&quot;&gt;building trust, giving ownership, and avoiding surprises&lt;/a&gt;. That figuring out &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2011/11/29/how-we-work/&quot;&gt;a process that works&lt;/a&gt; for your team matters. That &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2014/05/22/deliberate-iteration/&quot;&gt;deliberate iteration&lt;/a&gt; paired with discipline is a driver for success. That &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2013/05/15/business-with-pleasure/&quot;&gt;it is important to know your weaknesses and deal find ways to deal with them&lt;/a&gt;. That &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2012/09/07/focus/&quot;&gt;focus&lt;/a&gt; is an ongoing struggle. That solving the right problem, doing the simplest thing first, and failing fast &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2013/09/16/new-team-and-lessons-learned/&quot;&gt;are things I value&lt;/a&gt;. That listening to &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2014/02/13/sleep-apnea-survivor/&quot;&gt;friends and family can save your life&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But I’ve written about all of those things already. So what haven’t I written about?&lt;/p&gt;
&lt;h3 id=&quot;retrospectives&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/ten-years-a-software-engineer/#retrospectives&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Retrospectives&lt;/h3&gt;
&lt;p&gt;This blog post is a result of reflecting on the past 10 years so I figured talking about my process for retrospectives would be fitting. Consistent retrospectives are probably the largest contributing factor to who I am today compared to 10 years ago.&lt;/p&gt;
&lt;p&gt;Taking time every day, week, month, and year to analyze decisions I’ve made, actions I’ve taken, and the actual outcomes versus my expectations is how I learn what I need to change who I am into who I want to be. A recent example, taken from a personal &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2014/11/17/swot-analysis/&quot;&gt;SWOT analysis&lt;/a&gt;, was that I have a tendency to talk over my peers when I get excited about an idea ☹️ As soon as I identified this behavior I started working to change it.&lt;/p&gt;
&lt;p&gt;A retrospective goes something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set aside distraction free time.&lt;/li&gt;
&lt;li&gt;Think about something that has happened, whether it was something I did or that happened to me.&lt;/li&gt;
&lt;li&gt;Consider the situation, how I feel about it, what I can do better the next time I’m in that situation.&lt;/li&gt;
&lt;li&gt;Follow up homework if needed. This could be anything from repeating the situation so I can get better at handling to reading about the subject to learn how other people think about it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Setting aside time is the hardest part for me, so I’m always keeping an eye out for these distractions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Social media&lt;/li&gt;
&lt;li&gt;Entertainment (TV/movies/podcasts/audiobooks)&lt;/li&gt;
&lt;li&gt;Speeding through life&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Likewise these are opportunities for reflection that I’m constantly looking for:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;After personal devotions (or meditation)&lt;/li&gt;
&lt;li&gt;After receiving feedback (good or bad)&lt;/li&gt;
&lt;li&gt;After pretty much every conversation&lt;/li&gt;
&lt;li&gt;After reading, watching, or listening to something (entertainment made both lists!)&lt;/li&gt;
&lt;li&gt;The end of the day, week, month, and year&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I like to write down the things I’ve learned through my retrospectives and I often use frameworks like Start/Stop/Keep or a SWOT analysis to help me organize my thoughts and find patterns. This gives me a great opportunity to find repeating themes over the years and track my personal progress. And sometimes it even turns into a blog post 😃&lt;/p&gt;
&lt;h2 id=&quot;where-do-i-see-myself-going-in-the-future%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/ten-years-a-software-engineer/#where-do-i-see-myself-going-in-the-future%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Where do I see myself going in the future?&lt;/h2&gt;
&lt;p&gt;I’ve been interested in &lt;a href=&quot;https://en.wikipedia.org/wiki/Machine_learning&quot;&gt;Machine Learning&lt;/a&gt; for the past year and recently took a new position at GitHub working on the Security team where I get to use my current skillset and learn some ML and computational statistics techniques. I’m really enjoying it so far and I think I’ll be focused on Machine Learning and Artificial Intelligence for the next few years. I’ve also been hardware hacking as a hobby for the past few years so maybe I’ll get to build that robot butler someday.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/ten-years-a-software-engineer/robot-walk.gif&quot; alt=&quot;robot-walk&quot; /&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Intention vs Perception</title>
    <link href="https://jonmagic.com/posts/intention-vs-perception/"/>
    <updated>2014-11-23T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/intention-vs-perception/</id>
    <content type="html">&lt;p&gt;It is interesting to study the gap between the intention of communication and the perception of communication in the context of leadership. “We’re going to do X going forward” can be interpreted as “You’re doing a crappy job at Y so we’re going to try X now” or “We decided that it is better to do X instead of Y because we had a meeting you weren’t invited to since we don’t really value your opinion” and the list of interpretations goes on.&lt;/p&gt;
&lt;p&gt;In my experience perception rarely matches intention, so figuring out how to change your message to get across what you actually intended is a fun challenge.&lt;/p&gt;
&lt;p&gt;There are probably many ways to do it successfully, but I only have experience with a few so I’ll share those (YMMV).&lt;/p&gt;
&lt;h3 id=&quot;earn-the-trust-of-those-impacted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/intention-vs-perception/#earn-the-trust-of-those-impacted&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Earn the trust of those impacted&lt;/h3&gt;
&lt;p&gt;Earning trust takes time. Time spent learning about someone, how to communicate with them, what they are passionate about, understanding their fears.&lt;/p&gt;
&lt;p&gt;I like to take people out to lunch, video chat, pair program on a code kata, or help with a problem they are having.&lt;/p&gt;
&lt;p&gt;This is the first opportunity to be a servant leader I think. Serve the people you lead and, more likely than not, you will gain their respect and trust.&lt;/p&gt;
&lt;h3 id=&quot;give-ownership&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/intention-vs-perception/#give-ownership&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Give ownership&lt;/h3&gt;
&lt;p&gt;When someone is going to change the way I work, what I’m working on, or who I’m working with, the psychological toll of that change can be greatly reduced if I feel like I have control over my own destiny.&lt;/p&gt;
&lt;p&gt;I look forward to working with leaders that engage me and get me involved in the decision-making process. They ask things like “What do you think about doing X instead of Y; what would be the benefits and what would be the drawbacks?”&lt;/p&gt;
&lt;p&gt;Asking for, listening, and reacting to my feedback gives me ownership of an idea, even if it was not my own. Reacting is not necessarily implementing my feedback, but this process of involvement changes the way the idea was communicated and perceived.&lt;/p&gt;
&lt;h3 id=&quot;avoid-surprises&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/intention-vs-perception/#avoid-surprises&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Avoid surprises&lt;/h3&gt;
&lt;p&gt;There is a bonus to talking one-on-one with everyone on a team about an idea before announcing it at a meeting or in an email. You avoid surprises. Turns out not many people enjoy surprises, unless it’s a surprise party.&lt;/p&gt;
&lt;p&gt;Having an opportunity to hear and discuss an idea before it is executed gives me time to get comfortable with it. If you have gained my trust then I also feel like I have time to provide feedback before the idea becomes reality.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>SWOT Analysis</title>
    <link href="https://jonmagic.com/posts/swot-analysis/"/>
    <updated>2014-11-17T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/swot-analysis/</id>
    <content type="html">&lt;p&gt;In college I learned how to do a &lt;a href=&quot;http://en.wikipedia.org/wiki/SWOT_analysis&quot;&gt;SWOT analysis&lt;/a&gt; and I’ve been using it in one form or another at work and in my personal life ever since.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 5-19-2015:&lt;/strong&gt; The authors of &lt;a href=&quot;http://formswift.com/swot-analysis-guide&quot;&gt;this amazing SWOT guide&lt;/a&gt; reached out to me to let me know about their work. After reading my simple how to below, &lt;a href=&quot;http://formswift.com/swot-analysis-guide&quot;&gt;check out their full guide&lt;/a&gt; to learn even more.&lt;/p&gt;
&lt;p&gt;So why do I care about my strengths, weaknesses, opportunities, and threats? Because I’m ambitious (both a strength and a weakness) and I constantly want to be better at everything I do and I want everything I’m a part of to constantly be improving.&lt;/p&gt;
&lt;p&gt;How do I identify and analyze these areas with regard to my personal life or work life? I choose what I want to analyze (myself, a friend asking for feedback, an area of my job) and then sit down with a pen and paper.&lt;/p&gt;
&lt;p&gt;I start by drawing a vertical line down the center of the page and then a horizontal line across the page. I now have four quadrants and I label them S, W, O, and T.&lt;/p&gt;
&lt;p&gt;Next I write down weaknesses and then strengths in their quadrants. You probably won’t be sharing this analysis with anyone so be brutally honest. Depending on your disposition you may find it easier to write down weaknesses than strengths, or vice versa. With time you’ll get better at identifying both if you practice consistently.&lt;/p&gt;
&lt;p&gt;Once I have an understanding of strengths and weaknesses, it is usually pretty easy to identify opportunities that capitalize on strengths and work to turn weaknesses into strengths. Likewise, threats are anything that could turn a strength into a weakness or further entrench an existing weakness.&lt;/p&gt;
&lt;p&gt;Now you have to decide what action to take based on the opportunities and threats. After repeating this process a few times you start to see patterns and improve your process even more. Here’s an analysis I did on myself a few months back with regard to my work life.&lt;/p&gt;
&lt;p&gt;I noticed after this analysis that my first opportunity, “listen more”, was the most important thing to act on because it addressed several of my weaknesses while building on my strengths and lessened at least one threat. This is one pattern I look for now: opportunities that apply to multiple concerns.&lt;/p&gt;
&lt;p&gt;Try a SWOT Analysis next time you want to level up.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Deliberate Iteration</title>
    <link href="https://jonmagic.com/posts/deliberate-iteration/"/>
    <updated>2014-05-22T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/deliberate-iteration/</id>
    <content type="html">&lt;p&gt;I’ve never been good at New Years resolutions but this year has been different. Starting the year I decided to iterate on life in a much more deliberate way. Here are the results.&lt;/p&gt;
&lt;h3 id=&quot;writing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/deliberate-iteration/#writing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Writing&lt;/h3&gt;
&lt;p&gt;I’m starting to understand how important it is to measure iterations in order to continously improve, instead of just changing things for the sake of change. Writing things down is the best way I have found to measure change.&lt;/p&gt;
&lt;p&gt;I’m on my sixth notebook for the year. I write notes when I get up in the morning, when I’m in meetings, when I handle email, when I’m reading, all throughout the day really.&lt;/p&gt;
&lt;p&gt;When I sense change I can look back at my notes and see the evolution of an idea. After testing change to see if the results are better than previous results I can identify patterns in the ideas I wrote down and repeat them or discard them.&lt;/p&gt;
&lt;h3 id=&quot;scheduling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/deliberate-iteration/#scheduling&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Scheduling&lt;/h3&gt;
&lt;p&gt;A few weeks ago I started using a calendar, like for real.&lt;/p&gt;
&lt;p&gt;(the first one is what my calendar looked like before I started using it consistently)&lt;/p&gt;
&lt;p&gt;The results have been dramatic. My work and life balance feels better than ever, I don’t feel like I’m dropping the ball anymore, and I rarely have to spend time thinking about what to do next.&lt;/p&gt;
&lt;p&gt;Before I only used to schedule meetings, dates I had to be at. This barely worked, I would sometimes miss meetings, or I would get anxious because I would suddenly have the feeling I had missed a meeting (even though I hadn’t).&lt;/p&gt;
&lt;p&gt;Now every Sunday evening I schedule the upcoming week, from 8am to 5pm every day (±1 hour). I use &lt;a href=&quot;http://readdle.com/products/calendars5/&quot;&gt;Calendars 5&lt;/a&gt; on my iPhone and it buzzes me 10 minutes before my next scheduled thing and I use &lt;a href=&quot;https://flexibits.com/fantastical&quot;&gt;Fantastical&lt;/a&gt; on the desktop.&lt;/p&gt;
&lt;p&gt;I have trained my brain to rely on the technology, by using it consistently. My error rates and anxious moments have been reduced to almost zero.&lt;/p&gt;
&lt;p&gt;I’m getting more done at work, I’m exercising more, and I’m spending more time relaxing. What am I spending less time doing? Spinning my wheels because I’m not sure what to do next.&lt;/p&gt;
&lt;h3 id=&quot;meetings&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/deliberate-iteration/#meetings&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Meetings&lt;/h3&gt;
&lt;p&gt;A lot of people have a visceral reaction to the word “meeting”. I used to but I don’t anymore. Every day I set aside time to meet with people. These meetings range from standups to work lunches to video calls to catch up with remote coworkers.&lt;/p&gt;
&lt;p&gt;As our company has grown I’ve come to realize how important it is to be deliberate about spending time with people and not just shipping code. Without connecting it is easy to quickly become lost.&lt;/p&gt;
&lt;p&gt;Every week I do at least one working lunch, I spend at least one hour on a video conference with a remote coworker, and I attend at least one planning meeting (whether it’s for my team or a team we interact with).&lt;/p&gt;
&lt;p&gt;Staying connected to coworkers has improved my mental health 10X as well as improving my value to the company by being able to connect people and ideas.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/deliberate-iteration/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Conclusion&lt;/h3&gt;
&lt;p&gt;Figure out how you are spending your time (maybe write it down?) and then look for things to change. Try using tools and doing things you think suck (calendars and meetings oh my!). Measure the results. Do it all over again.&lt;/p&gt;
&lt;h3 id=&quot;other-notes%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/deliberate-iteration/#other-notes%3A&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Other notes:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Writing things down is &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2011/10/03/just-write-it-down/&quot;&gt;a lesson I have learned before&lt;/a&gt; and forgotten. Why is it that good habits are so much harder to practice than bad ones?&lt;/li&gt;
&lt;li&gt;I’m writing this during my scheduled time off today 😃&lt;/li&gt;
&lt;li&gt;I’m also deliberate about meeting with people outside of my immediate circle, inside and outside of work.&lt;/li&gt;
&lt;li&gt;I realize some people will laugh at me for just now starting to use a calendar, but I think I’ve just now grown out of my 20’s “I enjoy chaos more than order” lifestyle.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Robots can do support too</title>
    <link href="https://jonmagic.com/posts/robots-can-do-support-too/"/>
    <updated>2014-02-28T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/robots-can-do-support-too/</id>
    <content type="html">&lt;p&gt;GitHub launched the &lt;a href=&quot;http://atom.io/&quot;&gt;Atom beta&lt;/a&gt; this week and the response has been great. As the first day was winding down a coworker suggested we write an FAQ and add a robot to answer the frequently asked questions in the IRC channel where people were congregating. Here’s how we taught &lt;a href=&quot;http://hubot.github.com/&quot;&gt;hubot&lt;/a&gt; to do support.&lt;/p&gt;
&lt;h3 id=&quot;questions-and-answers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/robots-can-do-support-too/#questions-and-answers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Questions and answers&lt;/h3&gt;
&lt;p&gt;First my coworker gathered the questions that were being asked over and over again:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;where do I get an invite?&lt;/li&gt;
&lt;li&gt;is there a windows or linux version of atom?&lt;/li&gt;
&lt;li&gt;how much will Atom cost?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next he wrote short and to the point answers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Are you looking for an atom invite? Go to &lt;a href=&quot;https://atom.io/&quot;&gt;https://atom.io/&lt;/a&gt; and put in your email, or join the #product-invitations room.&lt;/li&gt;
&lt;li&gt;Are you looking for a windows or linux version of atom? We don’t have one yet, but we will in the future.&lt;/li&gt;
&lt;li&gt;Were you inquiring in the channel about Atom’s price? We haven’t set a price yet, but expect it will be on par with the cost for similar editors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally he compiled the regular expressions that we could use in hubot to listen for people’s questions and then reply to them with the answers.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;invit(es?|ation)&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;windows&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;linux&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i
&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pric&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;ing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;cost&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;training-the-robot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/robots-can-do-support-too/#training-the-robot&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Training the robot&lt;/h3&gt;
&lt;p&gt;Meanwhile I used the &lt;a href=&quot;https://github.com/github/hubot/blob/master/docs/README.md&quot;&gt;Getting Started&lt;/a&gt; instructions to fire up a hubot instance.&lt;/p&gt;
&lt;p&gt;Using &lt;a href=&quot;http://shapeshed.com/setting-up-nodejs-and-npm-on-mac-osx/&quot;&gt;npm&lt;/a&gt; I installed the hubot and coffee-script packages.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; hubot coffee-script&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next I created the hubot instance.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;hubot &lt;span class=&quot;token parameter variable&quot;&gt;--create&lt;/span&gt; atomicHubot
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; atomicHubot
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; init &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Create atomicHubot&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I started hacking on the script (this is the final iteration with my work and my coworkers).&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Description:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#   Replying to people in atom channels on freenode.&lt;/span&gt;
#

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;robot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

  isNotified &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keyword&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; username&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;brain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;keyword&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;brain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;keyword&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;some&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; username &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; x

  replyTo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hear &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;invit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;es&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;ation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    username &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name

    &lt;span class=&quot;token keyword&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isNotified&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;invite&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; username&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;replyTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;username&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Are you looking for an atom invite?  Go to https://atom.io/ and put in your email, or join the #product-invitations room.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;brain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;invite&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;push username

  robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hear &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;windows&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;linux&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    username &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name

    &lt;span class=&quot;token keyword&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isNotified&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;winux&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; username&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;replyTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;username&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Are you looking for a windows or linux version of atom?  We don&#39;t have one yet, but we will in the future.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;brain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;winux&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;push username

  robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hear &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pric&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;ing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;cost&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    username &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name

    &lt;span class=&quot;token keyword&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isNotified&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;price&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; username&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;replyTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;username&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Were you inquiring in the channel about Atom&#39;s price?  We haven&#39;t set a price yet, but expect it will be on par with the cost for similar editors.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;brain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;price&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;push username&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every so often I would test the script in hubot’s shell console.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bin/hubot
&amp;gt; where can I get an invite?
hubot&amp;gt; jonmagic: Are you looking for an atom invite?  Go to https://atom.io/ and put in your email, or join the ##atom-invitations room.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next I installed the &lt;a href=&quot;https://github.com/nandub/hubot-irc&quot;&gt;irc adapter&lt;/a&gt; in atomicHubot.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; hubot-irc &lt;span class=&quot;token parameter variable&quot;&gt;--save&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Add irc adapter&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I needed atomicHubot to actually live on the internet and connect to the irc channel so I read the &lt;a href=&quot;https://github.com/github/hubot/blob/master/docs/deploying/heroku.md&quot;&gt;Deploying Hubot to Heroku&lt;/a&gt; instructions. These required that I have the &lt;a href=&quot;http://toolbelt.heroku.com/&quot;&gt;Heroku toolbelt&lt;/a&gt; installed.&lt;/p&gt;
&lt;p&gt;Step 1 was creating the application on Heroku and configuring it.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;heroku create atomichubot
heroku addons:add redistogo:nano
heroku config:set &lt;span class=&quot;token assign-left variable&quot;&gt;HEROKU_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;http://atomichubot.herokuapp.com
heroku config:set &lt;span class=&quot;token assign-left variable&quot;&gt;HUBOT_IRC_NICK&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;atomicHubot
heroku config:set &lt;span class=&quot;token assign-left variable&quot;&gt;HUBOT_IRC_ROOMS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;#channel-name&lt;/span&gt;
heroku config:set &lt;span class=&quot;token assign-left variable&quot;&gt;HUBOT_IRC_SERVER&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;irc.freenode.net
heroku config:set &lt;span class=&quot;token assign-left variable&quot;&gt;HUBOT_IRC_UNFLOOD&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step 2 was deploying to Heroku.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push heroku master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;That was it, I didn’t have to do any trouble shooting, atomicHubot connected to the irc channel and began fielding questions!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/robots-can-do-support-too/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Conclusion&lt;/h3&gt;
&lt;p&gt;Adding this hubot to the irc channel helped reduce the number of questions we had to answer and increased the speed at which common questions were answered.&lt;/p&gt;
&lt;p&gt;There are probably easier ways to setup auto reply answers in irc channels but hubot is a tool I’m familiar with and love to hack on. It only took a few minutes to setup and I’ll probably use the same technique in the future.&lt;/p&gt;
&lt;p&gt;This may not work for everyone but hubot sure helped out in a pinch, give it a try sometime. For tips on writing hubot scripts see my post &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2011/10/28/hubot-scripts-explained/&quot;&gt;hubot Scripts Explained&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Sleep Apnea Survivor</title>
    <link href="https://jonmagic.com/posts/sleep-apnea-survivor/"/>
    <updated>2014-02-13T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/sleep-apnea-survivor/</id>
    <content type="html">&lt;p&gt;Almost two years ago a friend and my wife saved my life. They got me to go see a doctor because my sleep was a mix of bone rattling snores, deathly silence, and gasps for air. If this sounds like someone you know, help save a life.&lt;/p&gt;
&lt;h2 id=&quot;i-should-have-listened-to-her&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/sleep-apnea-survivor/#i-should-have-listened-to-her&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; I should have listened to her&lt;/h2&gt;
&lt;p&gt;She wouldn’t say “I told you so” but I am certainly guilty of not following my wife’s advice several years ago to go see a doctor because I snored so loudly.&lt;/p&gt;
&lt;p&gt;I should have had more empathy for her situation, struggling to get sleep next to a roaring locomotive. Some nights she would go sleep in another room so she could be rested enough in the morning to go to work.&lt;/p&gt;
&lt;h2 id=&quot;resorting-to-the-bathtub&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/sleep-apnea-survivor/#resorting-to-the-bathtub&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Resorting to the bathtub&lt;/h2&gt;
&lt;p&gt;Then there was a night in Lansing Michigan where I shared a hotel room with three friends while attending a tech conference. In the morning I found one of them sleeping in the bathtub, another with headphones on, and the other with his head wrapped tightly in a pillow.&lt;/p&gt;
&lt;p&gt;When they woke up they were exhausted, trying to laugh it off in order to resist the urge to kill me (something discussed during the night). They described my sleep as snores loud enough to shake both beds in the room, interspersed with moments of sweet blissful silence, followed by sucking gasps for air.&lt;/p&gt;
&lt;h2 id=&quot;death-as-a-motivator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/sleep-apnea-survivor/#death-as-a-motivator&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Death as a motivator&lt;/h2&gt;
&lt;p&gt;Through all of this I still hadn’t taken the time to see a doctor. I didn’t think the snoring and silence were affecting my daily life, I wasn’t tired during the day, and going to see a doctor was a pain and would cost a lot of money.&lt;/p&gt;
&lt;p&gt;Plus I had read up on &lt;a href=&quot;http://en.wikipedia.org/wiki/Sleep_apnea&quot;&gt;sleep apnea&lt;/a&gt; treatments online and the thought of wearing a mask at night sounded awful. It seemed like all my searching just turned up stories of abandoned &lt;a href=&quot;http://en.wikipedia.org/wiki/Continuous_positive_airway_pressure&quot;&gt;CPAP&lt;/a&gt; machines.&lt;/p&gt;
&lt;p&gt;Finally a friend and coworker told me how his father went to bed one night and never woke up the next day and sleep apnea was the likely cause. This was the motivation I needed to finally go see a doctor.&lt;/p&gt;
&lt;h2 id=&quot;sleep-studied&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/sleep-apnea-survivor/#sleep-studied&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Sleep studied&lt;/h2&gt;
&lt;p&gt;In the spring of 2012 I had my first sleep study. I walked the two blocks from our home in Elkhart to the hospital, where they set me up in a small room that looked like a hotel room. Before going to bed they connected two dozen sensors to my head, chest, and legs.&lt;/p&gt;
&lt;p&gt;About 6 hours laster I woke up to go to the bathroom and they said they had enough data and sent me home. They told me I would hear back from the doctor in about two weeks.&lt;/p&gt;
&lt;h2 id=&quot;you-are-not-my-patient&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/sleep-apnea-survivor/#you-are-not-my-patient&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; You are not my patient&lt;/h2&gt;
&lt;p&gt;The afternoon after the sleep study I received a call from the doctors office asking if I could come in the next day. This was a surprise but I guessed the doctors business was just running a little slow so the sooner they got me in the faster they could collect their money.&lt;/p&gt;
&lt;p&gt;I arrived at the doctors office the next day, they took my weight, showed me into a small room, and then the nurse had me do the &lt;a href=&quot;http://umm.edu/programs/sleep/health/quizzes/sleepiness&quot;&gt;Epworth test&lt;/a&gt; and said the doctor would be in shortly.&lt;/p&gt;
&lt;p&gt;When the doctor entered the room he looked up from my chart, concern on his face, then did a double take when he saw me. He looked as if he was about to turn and leave but asked “are you Jon Hoyt”? I answered yes and the concern on his face turned to a look of confusion, but he sat down and the appointment proceeded.&lt;/p&gt;
&lt;p&gt;He explained that based on my study he was expecting a seriously overweight and exhausted male, someone over 300 pounds that looked like they hadn’t slept in years.&lt;/p&gt;
&lt;h2 id=&quot;diagnosed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/sleep-apnea-survivor/#diagnosed&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Diagnosed&lt;/h2&gt;
&lt;p&gt;This is when I learned just how close I came to death every night. The doctor explained that I stopped breathing 70 times per hour on average and my brain had to wake up just enough to kick start my breathing every time. This also meant I rarely, if ever, got the deep sleep we need to be truly rested.&lt;/p&gt;
&lt;p&gt;The doctor prescribed a CPAP machine and another sleep study to get the machine configured to the right settings to help me overcome my severe sleep apnea.&lt;/p&gt;
&lt;h2 id=&quot;10x-your-life&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/sleep-apnea-survivor/#10x-your-life&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; 10X your life&lt;/h2&gt;
&lt;p&gt;Within a week of getting the CPAP my life and my wife’s were completely changed. She was no longer fighting with the locomotive next to her and I was getting the deepest and most restful sleep I’d had in a decade.&lt;/p&gt;
&lt;p&gt;I went from 8-10 hours of sleep per night (I sleep without an alarm clock) to 6-8 hours of sleep per night and felt more rested and smarter. Yup, I felt smarter. I could reason out harder problems while programming, I could retain more information throughout the day, and I could communicate more easily at work.&lt;/p&gt;
&lt;p&gt;Almost two years later I can’t imagine life without my CPAP. So cheers to life, to sleep!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>New Team and Lessons Learned</title>
    <link href="https://jonmagic.com/posts/new-team-and-lessons-learned/"/>
    <updated>2013-09-16T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/new-team-and-lessons-learned/</id>
    <content type="html">&lt;p&gt;The past few months I have been building a new team at &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; focused on solving problems for our business teams. Here are a few valuable lessons we learned along the way.&lt;/p&gt;
&lt;h3 id=&quot;solving-the-right-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-team-and-lessons-learned/#solving-the-right-problem&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Solving the right problem&lt;/h3&gt;
&lt;p&gt;We solve problems for a living and we have one major constraint, our time. This means we need to be thoughtful in choosing which problems to solve. We cannot solve them all.&lt;/p&gt;
&lt;p&gt;We decided to solve employee expenses at GitHub by building our own expensing system. We had evaluated &lt;a href=&quot;http://expensify.com/&quot;&gt;3rd party services&lt;/a&gt; and while they did 90% of what we needed, that last 10% made it seem like it was worth doing on our own.&lt;/p&gt;
&lt;p&gt;What we failed to account for were the other opportunities, the other problems that needed solved, that ultimately would have a more lasting impact on GitHub.&lt;/p&gt;
&lt;p&gt;If we use our company vision, to help people &lt;a href=&quot;https://github.com/home&quot;&gt;build software better together&lt;/a&gt;, as a framework for deciding what to work on, choosing the right problem to solve becomes much easier.&lt;/p&gt;
&lt;p&gt;We should be sensitive to &lt;a href=&quot;http://en.wikipedia.org/wiki/Opportunity_cost&quot;&gt;opportunity costs&lt;/a&gt;. Solve the problem that will have the greatest impact with the lowest cost.&lt;/p&gt;
&lt;h3 id=&quot;failing-fast&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-team-and-lessons-learned/#failing-fast&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Failing fast&lt;/h3&gt;
&lt;p&gt;After choosing the wrong problem to solve we did not set clear goals so that we knew what success or failure meant. As a result it took us four months to realize we were working on the wrong thing.&lt;/p&gt;
&lt;p&gt;Our first goal was to ship a system that received receipts, connected them to transactions, provided automatic and manual classification, and then entered the data into our accounting system.&lt;/p&gt;
&lt;p&gt;The more I learn about software development, or solving any problem really, the more I realize a &lt;a href=&quot;http://en.wikipedia.org/wiki/Winning_percentage&quot;&gt;winning percentage&lt;/a&gt; requires breaking down problems (and their solutions) into smaller and smaller pieces. Shipping quickly and constant iteration mean faster course corrections and less costly failures.&lt;/p&gt;
&lt;p&gt;The fact that we could not easily break the expensing problem down into smaller pieces should have been a red flag.&lt;/p&gt;
&lt;p&gt;We can reduce the costs of failure, both emotionally and economically, if we fail fast. We can’t fail fast unless we ship quickly and iterate.&lt;/p&gt;
&lt;h3 id=&quot;do-the-simplest-thing-first&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-team-and-lessons-learned/#do-the-simplest-thing-first&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Do the simplest thing first&lt;/h3&gt;
&lt;p&gt;We also started building a platform for different teams (and apps) at GitHub to be able to easily invoice customers. We dreamt up the perfect platform for invoicing, without having tried the simplest thing first.&lt;/p&gt;
&lt;p&gt;The lie we often believe is that we understand what our constraints will be in a week, or a month, or six months and therefore we can save time by optimizing early. The truth is that we cannot foresee the future.&lt;/p&gt;
&lt;p&gt;In the end we learned that invoicing integration needed to be built inside of the products it serves first. After it has been proven it can possibly be extracted into a shared service. This sounds like more work in the long run, but ultimately this process can adapt to change more quickly and easily.&lt;/p&gt;
&lt;h3 id=&quot;one-more-thing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-team-and-lessons-learned/#one-more-thing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; One more thing&lt;/h3&gt;
&lt;p&gt;We could have avoided a lot of heartache and wasted resources if I had sought mentorship from people with more experience and context at GitHub.&lt;/p&gt;
&lt;p&gt;For long term success I need to constantly be learning, which means keeping an open mind and a humble spirit. I look forward to the journey
&#92;m/&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Business With Pleasure</title>
    <link href="https://jonmagic.com/posts/business-with-pleasure/"/>
    <updated>2013-05-15T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/business-with-pleasure/</id>
    <content type="html">&lt;p&gt;Hi, my name is Jon. I’m an addict. It does not matter what it is—if it makes me feel good, I do more of it.&lt;/p&gt;
&lt;h3 id=&quot;but-i-love-it-so-much!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/business-with-pleasure/#but-i-love-it-so-much!&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; But I Love It So Much!&lt;/h3&gt;
&lt;p&gt;I love my job, or more specifically, I love the work I get to do every day. Combine my love for work with my addiction problem and I end up working too much and spending too little time with my wife, or reading a book, or taking a walk.&lt;/p&gt;
&lt;p&gt;When things are going well at work I have a sense of accomplishment, which feels good, and &lt;a href=&quot;http://www.youtube.com/watch?v=48-tcRiBNj4&quot;&gt;I want more&lt;/a&gt;. How do you get more of something? You just keep doing the same thing over and over again that got you that good feeling, right?&lt;/p&gt;
&lt;h3 id=&quot;being-honest-with-myself&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/business-with-pleasure/#being-honest-with-myself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Being Honest With Myself&lt;/h3&gt;
&lt;p&gt;Right now I have no problem identifying that my line of thinking—doing more of something will result in more pleasure—is wrong. When I am in a destructive cycle I am completely blind to this fact.&lt;/p&gt;
&lt;p&gt;A destructive cycle is wanting one thing too much and being blind to the costs of achieving it. We also call this being obsessed with something. Ultimately these destructive cycles lead to some sort of meltdown for me when &lt;a href=&quot;http://en.wikipedia.org/wiki/Diminishing_returns&quot;&gt;increased input does not lead to an equal or greater increase in output&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;During a cycle I can’t stop thinking about whatever I’m obsessing about; I bring it to the dinner table, I bring it on a date, I go to bed with it. This damages my marriage and my mental health.&lt;/p&gt;
&lt;p&gt;Thankfully I am getting better at recognizing and breaking these cycles. I can’t take the credit though—my wife usually notices and starts to warn me early on. Learning to listen to her concerns is something I need to get better at. My last obsession lasted about ten days before she got through to me and I recognized the error of my ways. That was yesterday.&lt;/p&gt;
&lt;h3 id=&quot;shortening-the-cycle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/business-with-pleasure/#shortening-the-cycle&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Shortening the Cycle&lt;/h3&gt;
&lt;p&gt;There are a few things I am going to try to shorten this cycle. The first is obvious: listen to my wife. But what if you don’t live with someone?&lt;/p&gt;
&lt;p&gt;Recognize the signs. If I am spending less time doing things that relax me, like reading, walking with my dogs, or doing chores around the house, these are pretty good signs I’m not balancing work and life very well.&lt;/p&gt;
&lt;p&gt;I’m trying out a checklist of sorts. It is just a long list of non-work things that I can do each day. I made this list by observing what has been healthy for me in the past. I’m not going to check off everything on the list each day, but doing three or four a day is a good sign, and doing one or none is probably a bad sign.&lt;/p&gt;
&lt;p&gt;Make yourself accountable to your peers. If you know your signs, ask a coworker and friend to watch out for them. Most of the time someone other than yourself will recognize the signs much sooner than you will. There is a caveat: if you are going to make yourself accountable, you have to be willing to listen when they warn you.&lt;/p&gt;
&lt;p&gt;Getting it right feels great too. Excuse me while I add blogging to my list of non-work things to do.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Focus</title>
    <link href="https://jonmagic.com/posts/focus/"/>
    <updated>2012-09-07T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/focus/</id>
    <content type="html">&lt;p&gt;We just finished shipping a six month long milestone on one of our support tools at &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;. One lesson I learned along the way was focus.&lt;/p&gt;
&lt;h3 id=&quot;make-a-commitment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/focus/#make-a-commitment&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Make a Commitment&lt;/h3&gt;
&lt;p&gt;When I first heard about this project, the tool that handles all incoming support requests at GitHub, I was immediately intrigued and volunteered myself to help. Sitting down with the person who had developed the tool to that point and the support team, we came up with a few core things that had to happen, plus a lot of higher level todos.&lt;/p&gt;
&lt;p&gt;At the time, our support tool was just a front-end to a popular customer care service called &lt;a href=&quot;http://tenderapp.com/&quot;&gt;Tender&lt;/a&gt;, that was actually built by a couple GitHub employees in their previous lives. The service had done its job for a long time, but it was clear that our needs were changing, and that we couldn’t rely on a third party service to meet them.&lt;/p&gt;
&lt;p&gt;So, I made the commitment to help achieve this goal and get our support system running on its own as a full fledged application inside of GitHub. I am not actually sure if I would have made this commitment if I had read through the codebase and understood what a long road it would be. Thankfully, in my gung-ho sorta way I just signed up on the spot.&lt;/p&gt;
&lt;h3 id=&quot;frame-all-questions-%26-answers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/focus/#frame-all-questions-%26-answers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Frame All Questions &amp;amp; Answers&lt;/h3&gt;
&lt;p&gt;Having made the commitment, I dove into the project head first. I quickly became the primary developer on the project, with people coming in from other teams to help for a few weeks before returning to their other work (thankfully &lt;a href=&quot;http://twitter.com/spicycode&quot;&gt;@spicycode&lt;/a&gt; joined later as a full time member of the team). Along the way I learned that being the primary person responsible also meant that people came to me with their needs and wants.&lt;/p&gt;
&lt;p&gt;Initially, being a people pleaser, I did everything in my power to fulfill their wishes and desires or promised to work on what they needed later. Quickly this became unsustainable and I became frustrated with my inability to fulfill those requests.&lt;/p&gt;
&lt;p&gt;Then I learned the right way to answer questions when asked. I had to frame every question, every want, every wish, in the context of my original commitment. Would satisfying their need further our core goals, and did I have the resources necessary to accomplish it?&lt;/p&gt;
&lt;h3 id=&quot;learn-to-say-no&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/focus/#learn-to-say-no&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Learn To Say No&lt;/h3&gt;
&lt;p&gt;Most of the time during the last six months that answer ended up being &lt;strong&gt;no&lt;/strong&gt;. This was especially tough for me, I hate saying no, but I had to learn how to do it or risk losing my sanity and disappoint a lot of people.&lt;/p&gt;
&lt;p&gt;Thankfully in many cases I didn’t have to say a flat no – instead, we would channel the energy and idea into a feature request that we could talk about more down the road. All of these feature requests were recorded in GitHub Issues and revisited over the following months, taking new shapes, and in some cases being made obsolete by better and newer ideas.&lt;/p&gt;
&lt;p&gt;Along the way, we implemented just enough to keep our support team happy, with all of their hair intact. Mostly, we focused on our core goals.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/focus/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Conclusion&lt;/h3&gt;
&lt;p&gt;Last night at midnight we flipped the switch to route all support requests thru our new backend. We still use Tender in a limited capacity for old discussions that are still open, but as time passes those will be archived and eventually we will be able to remove Tender completely as a dependency.&lt;/p&gt;
&lt;p&gt;In six months, we laid a solid foundation for the future of support at GitHub by staying focused.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>My Trip to Verona</title>
    <link href="https://jonmagic.com/posts/my-trip-to-verona/"/>
    <updated>2012-05-19T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/my-trip-to-verona/</id>
    <content type="html">&lt;p&gt;As my plane broke through the clouds, descending into Verona, my eyes were met with seemingly endless farm land, a patchwork quilt, broken up by small patches of trees and wandering erratic roads.&lt;/p&gt;
&lt;h3 id=&quot;day-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-trip-to-verona/#day-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Day 1&lt;/h3&gt;
&lt;p&gt;We landed at the small airport and for the first time in a decade I felt like a foreigner. I was in Verona for &lt;a href=&quot;http://2012.jsday.it/&quot;&gt;jsDay&lt;/a&gt;, having been given the opportunity to speak.&lt;/p&gt;
&lt;p&gt;After exchanging dollars for euros I hailed a cab. My driver must have been training for the grand prix as we zigzagged and raced around cars at 140km/h. The exhilarating ride ended at the hotel and my original notion that Verona was mostly flat was thoroughly dispelled.&lt;/p&gt;
&lt;p&gt;Soon I met with my &lt;a href=&quot;http://github.com/bkeepers&quot;&gt;coworker&lt;/a&gt; and his wife who were in Verona on holiday and we jumped on a bus for &lt;a href=&quot;http://en.wikipedia.org/wiki/Lake_Garda&quot;&gt;Lago di Garda&lt;/a&gt;. We spent the afternoon catching up, enjoying the scenery, and eating the local fare.&lt;/p&gt;
&lt;p&gt;Jet lag began to sneak up on me as the sun moved into the western sky. We returned to the hotel and began making dinner plans, but before we could execute I ran into other speakers from the conference.&lt;/p&gt;
&lt;p&gt;Introductions were made, plans were changed, and the &lt;a href=&quot;http://en.wikipedia.org/wiki/Spritz_(alcoholic_beverage)&quot;&gt;spritz&lt;/a&gt; began to flow. At a local Pizzeria, one among hundreds in a several kilometer area apparently, we feasted on thin crust delicacies.&lt;/p&gt;
&lt;p&gt;We talked into the night, closing the pizzeria and then the hotel bar. A &lt;a href=&quot;http://twitter.com/shvi&quot;&gt;rag&lt;/a&gt; &lt;a href=&quot;http://twitter.com/seldaek&quot;&gt;tag&lt;/a&gt; group of &lt;a href=&quot;https://twitter.com/maboa&quot;&gt;many&lt;/a&gt; &lt;a href=&quot;http://twitter.com/couac&quot;&gt;nationalities&lt;/a&gt;, daring each other to try the &lt;a href=&quot;http://en.wikipedia.org/wiki/Grappa&quot;&gt;grappa&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally around 3am I collapsed into bed, exhausted from the last 37 hours of travel and new culture acclimation.&lt;/p&gt;
&lt;h3 id=&quot;day-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-trip-to-verona/#day-2&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Day 2&lt;/h3&gt;
&lt;p&gt;The conference began with a &lt;a href=&quot;http://twitter.com/#!/jsconfit/status/202676559918804993/photo/1&quot;&gt;spritz&lt;/a&gt;. The talks were great and it was refreshing to catch up on the world of Javascript since I’ve been so deep in Ruby for the past six months. Twice I had to retire to my room to lay down for a bit, jet lagged and exhausted.&lt;/p&gt;
&lt;p&gt;Lunch was catered by the conference center and I mostly feasted on salad, cuts of meat and cheese, carrots, and cooked greens. Red wine was served and rivaled anything I’ve had back home.&lt;/p&gt;
&lt;p&gt;At this point I must have been meeting new people at a rate of six or more per hour. English truly is the international language, at least in the programming community.&lt;/p&gt;
&lt;p&gt;In the evening they took all of the speakers to the tallest tower in Verona, where I scaled 368 steps and then faced one of my worst fears, heights. It is so strange that I have no problem getting in an aluminum tube that hurtles around the world many thousands of feet above the ground without a second thought, but looking down from a twenty story tower makes me weak in the knees.&lt;/p&gt;
&lt;p&gt;After descending we walked across the piazza and sat down at the finest restaurant in Verona. The first glass was filled with Prosecco and I began meeting everyone around the table. Two Californians, a few from Italy, a couple from Germany, and the GitHub delegation.&lt;/p&gt;
&lt;p&gt;We all enjoyed conversing, the three course meal and dessert, and of course more red wine. The meal was good but I felt like it was not much different in style or quality from what my wife and I cook at home. The dessert on the other hand, a cream with nuggets of pure chocolate heaven, was fantastic.&lt;/p&gt;
&lt;p&gt;After dinner we were bussed back to the hotel and a large number of us headed back to the pizzeria from the pervious night to join the conference attendees. I met more people, sampled the local beer, and once again we closed the place.&lt;/p&gt;
&lt;p&gt;Once back to the hotel I settled in at a table in the bar with a Norwegian living in Italy and a &lt;a href=&quot;http://twitter.com/seldaek&quot;&gt;Belgian&lt;/a&gt; living in Switzerland. We talked into the wee hours of the morning over a couple of beers, discussing everything from nationalized healthcare to the perfect bolognese recipe.&lt;/p&gt;
&lt;p&gt;I finally climbed the four flights of steps to my room around 4am and kissed the mattress.&lt;/p&gt;
&lt;h3 id=&quot;day-3&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-trip-to-verona/#day-3&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Day 3&lt;/h3&gt;
&lt;p&gt;Going to bed so late prevented me from waking up in time to see Douglas Crockford talk in the morning, which was definitely a disappointment. I did make it to a few talks however and it was interesting to see what libraries and tools people were using around the world.&lt;/p&gt;
&lt;p&gt;Right before my talk I took a power nap and awoke with an idea for how to engage my audience a bit more.&lt;/p&gt;
&lt;p&gt;Before leaving my room I grabbed some &lt;a href=&quot;http://en.wikipedia.org/wiki/Mostarda&quot;&gt;mostarda&lt;/a&gt; I had purchased and on the way to the conference rooms I ordered a spritz from the bar.&lt;/p&gt;
&lt;p&gt;As I began my talk about &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2012/05/19/hubot-img-me-woman-laughing-alone-with-salad/&quot;&gt;Hubot the robot butler&lt;/a&gt; I walked out into the audience and asked whether they liked it when someone did something nice for them. They didn’t answer immediately so I singled out one young lady and asked her if she would like the mostarda or the spritz. She said either so I gave her the spritz and then held up the mostarda and asked who wanted it. A gentleman in the back said sure and I passed it to him and then headed to the front to start my talk. I had broken the ice, demonstrated a servants heart (a butlers heart!), and calmed myself down in the process by having some one on one interaction with the audience.&lt;/p&gt;
&lt;p&gt;It felt like the rest of my talk went really well, my energy level was high, I didn’t stumble, and I actually hit my allotted time perfectly! There were even a few questions and light applause. But later I noticed there was only one tweet and no one really came up to ask me more about Hubot, so I’m wondering if either I spoke too quickly and was hard to understand or if my audience just didn’t really need their own robot butler.&lt;/p&gt;
&lt;p&gt;After the talk the usual wave of relief washed over me mixing with the waning adrenaline. Now it was time to prepare for hosting a GitHub drinkup!&lt;/p&gt;
&lt;p&gt;I found a group to have dinner with and we began our trek across the city. We sat down to a nice meal and the conversation was relaxed. Then I left them a bit early to ensure our venue was ready for the drinkup.&lt;/p&gt;
&lt;p&gt;Arriving at the &lt;a href=&quot;http://www.kbh.it/&quot;&gt;Kulmbacher Bier-Haus&lt;/a&gt; I found my coworker and his wife already there. I went inside and made friends with Tony the bartender, an energetic young fellow with blond hair. The entire staff were dressed up in cheesy Bavarian garb that put a smile on your face.&lt;/p&gt;
&lt;p&gt;As the designated hour approached people started arriving and we took our place in the back of the restaurant. My coworker and I took turns greeting each new group that wandered in, asking them what they were working on, what they were excited about in their careers, and answering any questions they had for us. One question was oft repeated: “how do I sell my boss or clients on using git.” I honestly struggled to come up with anything they hadn’t already tried. Definitely something I need to study more and work on, as I haven’t ever had to sell git to a boss or client, I just started using it and didn’t give them a choice. Unfortunately that doesn’t work for everyone.&lt;/p&gt;
&lt;p&gt;After the successful drinkup a small group of us migrated to a quiet watering hole down the road, continuing unfinished conversations over a grappa.&lt;/p&gt;
&lt;p&gt;The bar closed and we walked back to the hotel, me in the lead, arriving back at nearly 4am. With jsDay over I rested my head on the pillow and had my first good long night of sleep since arriving.&lt;/p&gt;
&lt;h3 id=&quot;day-4&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-trip-to-verona/#day-4&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Day 4&lt;/h3&gt;
&lt;p&gt;As my eyes opened I realized it was nearly lunchtime, so I jumped up, dressed, and grabbed my Kindle. Leaving the hotel I found myself heading back to the trusty Pizzeria San Marco. I ordered wine and a pizza with prosciutto, fungi (mushrooms), and mozzarella. I spent my lunch reading &lt;a href=&quot;http://objectsonrails.com/&quot;&gt;Objects on Rails&lt;/a&gt; and thinking.&lt;/p&gt;
&lt;p&gt;When I was done a nap seemed in order so I returned to the hotel and layed down for a few more hours. Waking up for the second time that day I wasn’t sure what to do so I loaded my messenger bag with laptop and Kindle and headed towards the city center. It was a fascinating hike with beautiful sites and delicious smells, set to a soundtrack from my iPhone. I started with &lt;a href=&quot;http://www.rdio.com/artist/Danger_Mouse/album/Rome/&quot;&gt;Rome&lt;/a&gt; and then moved on to &lt;a href=&quot;http://www.rdio.com/artist/Django_Reinhardt/album/Sultan_Of_Swing/&quot;&gt;The Sulton of Swing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While crossing over the Ponte Pietra bridge into the touristy center I saw many people with Gelato so I tracked down the source and bought a small cup of Strachiatella, then found a bench overlooking the river and took my time enjoying the purchase. Around dinner time I found a touristy place and had a somewhat awful meal (never go touristy!).&lt;/p&gt;
&lt;p&gt;Dinner complete I trekked back to the hotel and found a table in the bar to sit, read, and relax at. I enjoyed my last glass of wine in Italy (for this trip at least) and read &lt;a href=&quot;http://practicingruby.com/&quot;&gt;Practicing Ruby&lt;/a&gt; articles and watched &lt;a href=&quot;http://destroyallsoftware.com/&quot;&gt;Destroy All Software&lt;/a&gt; videos. Completely exhausted from socializing I avoided the party that night and retired to my room early.&lt;/p&gt;
&lt;p&gt;After a few short hours of sleep I rose, packed, and grabbed a much more relaxed cab ride to the airport.&lt;/p&gt;
&lt;p&gt;As my plane rose into the sky I said “Ciao Verona” and began writing my tale.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>HUBOT img me woman laughing alone with salad</title>
    <link href="https://jonmagic.com/posts/hubot-img-me-woman-laughing-alone-with-salad/"/>
    <updated>2012-05-19T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/hubot-img-me-woman-laughing-alone-with-salad/</id>
    <content type="html">&lt;p&gt;In the past month I’ve had the opportunity to present this talk twice, first in London England and then in Verona Italy.&lt;/p&gt;
&lt;p&gt;Before joining GitHub I met &lt;a href=&quot;http://zachholman.com/&quot;&gt;Zach Holman&lt;/a&gt; from GitHub at a conference in Colorado and heard about &lt;a href=&quot;http://hubot.github.com/&quot;&gt;Hubot&lt;/a&gt;. As soon as Hubot was released as open source we started using him at Ordered List and I blogged a simple &lt;a href=&quot;http://theprogrammingbutler.com/blog/archives/2011/10/28/hubot-scripts-explained/&quot;&gt;script writing tutorial&lt;/a&gt;, which is still my most popular blog post day to day.&lt;/p&gt;
&lt;p&gt;After joining GitHub I got up the nerve to write and submit a talk proposal and lo and behold two out of three of the conferences I submitted to accepted my talk. I gave this presentation first in London at &lt;a href=&quot;http://devslovebacon.com/&quot;&gt;DevsLoveBacon&lt;/a&gt; and you can find the &lt;a href=&quot;http://devslovebacon.com/speakers/jonathan-hoyt&quot;&gt;video of my talk&lt;/a&gt; on their site. A few weeks later I traveled to &lt;a href=&quot;http://2012.jsday.it/&quot;&gt;jsDay in Verona Italy&lt;/a&gt; and presented a second time!&lt;/p&gt;
&lt;p&gt;Here are the slides from my presentation.&lt;/p&gt;
&lt;p&gt;If you have any feedback on how I can make the talk better or any questions about Hubot please send it via &lt;a href=&quot;http://twitter.com/jonmagic&quot;&gt;Twitter @jonmagic&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Speaker Deck Goes Full-screen</title>
    <link href="https://jonmagic.com/posts/speaker-deck-goes-full-screen/"/>
    <updated>2012-04-04T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/speaker-deck-goes-full-screen/</id>
    <content type="html">&lt;p&gt;I’m really excited to let you know that we’ve added full-screen support to presentations on &lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt;. This feature has been percolating for awhile, going thru several iterations before we found a solution that we really liked.&lt;/p&gt;
&lt;p&gt;We are using the &lt;a href=&quot;https://developer.mozilla.org/en/DOM/Using_full-screen_mode&quot;&gt;new full-screen API’s&lt;/a&gt; available in Webkit based browsers and Firefox. There were a few obstacles we had to overcome, mostly just learning how the API’s actually worked, specifically how to make an element inside an iFrame go fullscreen (make sure to add the allow flags to your iframe tag).&lt;/p&gt;
&lt;p&gt;In the process we learned a ton of great stuff that will let us do some pretty cool things in the future. The way we designed full-screen will let us use higher resolution slides in the future as well (you know, in case we decide to start encoding them at the resolution of that new device Apple just released).&lt;/p&gt;
&lt;p&gt;Here’s a presentation I did awhile back, check it out in full-screen!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Scriptular</title>
    <link href="https://jonmagic.com/posts/scriptular/"/>
    <updated>2012-03-05T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/scriptular/</id>
    <content type="html">&lt;p&gt;Ever since &lt;a href=&quot;http://hubot.github.com/&quot;&gt;Hubot&lt;/a&gt; was released I’ve been regular expressing myself. Here is a tool I built to make testing regular expressions in JavaScript easier.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://rubular.com/&quot;&gt;Rubular&lt;/a&gt; was my go-to for testing regex in the past, but it’s targeted at Ruby so I went in search of a nice editor for JavaScript regular expressions. Unfortunately my search yielded no results. Fortunately I had the tools and experience to build one!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://scriptular.com/&quot;&gt;Scriptular&lt;/a&gt; is the fruit of my labor. I modeled Scriptular after Rubular with one major difference: it doesn’t have a backend service—everything runs in the browser.&lt;/p&gt;
&lt;p&gt;I am really excited about Scriptular; I think it will be useful for developers everywhere. With its current implementation, you can test how a regex reacts in any browser by loading Scriptular in that browser and testing the regex. In the future, I would also like to have a backend service for testing server-side JavaScript implementations like V8.&lt;/p&gt;
&lt;p&gt;So go &lt;a href=&quot;http://scriptular.com/&quot;&gt;kick the tires&lt;/a&gt;, give it a &lt;a href=&quot;http://scriptular.com/&quot;&gt;spin around the block&lt;/a&gt;, and let me know what you think. If you would like to help on the project, please &lt;a href=&quot;http://github.com/jonmagic/scriptular&quot;&gt;check it out on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Update: Thanks to &lt;a href=&quot;http://opensoul.org/&quot;&gt;@bkeepers&lt;/a&gt; for contributing the design.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>New Tabs and Cucumber</title>
    <link href="https://jonmagic.com/posts/new-tabs-and-cucumber/"/>
    <updated>2012-02-07T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/new-tabs-and-cucumber/</id>
    <content type="html">&lt;p&gt;While working on an internal app at &lt;a href=&quot;http://github.com/&quot;&gt;GitHub&lt;/a&gt; I had to write a &lt;a href=&quot;http://cukes.info/&quot;&gt;cucumber&lt;/a&gt; scenario that ran expectations against a new tab that was opened. Here is how I did it.&lt;/p&gt;
&lt;h3 id=&quot;the-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-tabs-and-cucumber/#the-code&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Code&lt;/h3&gt;
&lt;p&gt;Searching around the internet, I finally found a tip on &lt;a href=&quot;http://stackoverflow.com/questions/3104348/ruby-on-rails-cucumber-how-do-i-follow-a-link-that-opens-a-new-window&quot;&gt;StackOverflow&lt;/a&gt; that got me moving in the right direction. In this context tabs are referred to as windows.&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;driver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;switch_to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;driver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;window_handles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;last&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code grabs the browser object and calls switch_to window on it and passes in the last opened window.&lt;/p&gt;
&lt;p&gt;Now all we need to do is wrap this in a step so we can use it in our scenarios.&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;When &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;I&lt;/span&gt; access the &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; tab$&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;driver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;switch_to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;driver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;window_handles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;last&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-caveat&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-tabs-and-cucumber/#the-caveat&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Caveat&lt;/h3&gt;
&lt;p&gt;This will only work if you are using &lt;a href=&quot;http://seleniumhq.org/docs/&quot;&gt;selenium-webdriver&lt;/a&gt;. It will &lt;a href=&quot;https://github.com/thoughtbot/capybara-webkit/issues/47&quot;&gt;not work with capybara-webkit&lt;/a&gt; unfortunately. So I switched to selenium, but I told it to use chrome instead of the default firefox and it still works great!&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;Capybara&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;javascript_driver &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:selenium&lt;/span&gt;
Capybara&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;register_driver &lt;span class=&quot;token symbol&quot;&gt;:selenium&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;app&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
  Capybara&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Selenium&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Driver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:browser&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:chrome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-finale&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-tabs-and-cucumber/#the-finale&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Finale&lt;/h3&gt;
&lt;p&gt;Now its time to see the step in action. Notice I had to tag the feature with @javascript so that it uses the selenium webdriver.&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;@javascript&lt;/span&gt;
&lt;span class=&quot;token symbol&quot;&gt;Feature&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Open a discussion

  &lt;span class=&quot;token symbol&quot;&gt;Scenario&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; staff opens a discussion with the mouse
    Given the following users exist&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; username   &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; email                 &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; test&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;user  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; integration&lt;span class=&quot;token variable&quot;&gt;@test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;com  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
    And &lt;span class=&quot;token constant&quot;&gt;I&lt;/span&gt; am on the triage page
    When &lt;span class=&quot;token constant&quot;&gt;I&lt;/span&gt; follow &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Can&#39;t get git running on my mac&quot;&lt;/span&gt;&lt;/span&gt;
    And &lt;span class=&quot;token constant&quot;&gt;I&lt;/span&gt; access the &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; tab
    Then &lt;span class=&quot;token constant&quot;&gt;I&lt;/span&gt; should be on the discussion page &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;5786909&quot;&lt;/span&gt;&lt;/span&gt;
    And &lt;span class=&quot;token constant&quot;&gt;I&lt;/span&gt; should see &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Can&#39;t get git running on my mac&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The link that I follow opens the new page in a new tab, I select the new tab, then run my expectations against it.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Being acquired doesn&#39;t have to suck</title>
    <link href="https://jonmagic.com/posts/being-acquired-doesnt-have-to-suck/"/>
    <updated>2012-01-08T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/being-acquired-doesnt-have-to-suck/</id>
    <content type="html">&lt;p&gt;It has been a month since &lt;a href=&quot;https://github.com/blog/993-ordered-list-is-a-githubber&quot;&gt;Ordered List was acquired by GitHub&lt;/a&gt; and our team of 5 joined their team of 50, and it hasn’t sucked at all. Here are some observations on how to remove the suck from acquisitions.&lt;/p&gt;
&lt;h3 id=&quot;the-suck&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/being-acquired-doesnt-have-to-suck/#the-suck&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Suck&lt;/h3&gt;
&lt;p&gt;My general attitude towards acquisitions the past few years has been fairly negative. I’ve seen too many people and products we love be acquired and the people only stick around until their stock vests and the products are shut down or perverted into something hideous.&lt;/p&gt;
&lt;p&gt;With all that negative sentiment you would think I would have fought for Ordered List to remain independent, but I assure you everyone on our team was not only on board with the acquisition but also excited about the opportunity.&lt;/p&gt;
&lt;p&gt;The number one problem after an acquisition are differences in culture. From how the individuals and teams work, to how they interact, how they are led, and how they are motivated.&lt;/p&gt;
&lt;p&gt;We would not have even considered joining GitHub if there were large differences in culture and any company looking at an acquisition should make sure this is the first thing they research and consider.&lt;/p&gt;
&lt;h3 id=&quot;the-reality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/being-acquired-doesnt-have-to-suck/#the-reality&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Reality&lt;/h3&gt;
&lt;p&gt;Both sides in this acquisition did their homework and didn’t just jump in without lots of serious consideration. Putting in this work ahead of time has made the actual integration of our teams virtually frictionless.&lt;/p&gt;
&lt;p&gt;My day to day work has not changed and yours shouldn’t have to either. This is definitely something to think about before an acquisition. Do they know what you do best and will they give you the opportunity to continue doing it? Thankfully I’m still working on the products I love and now I have a pool of talent and knowledge 10x greater than before to draw from.&lt;/p&gt;
&lt;p&gt;There is definitely more to keep track of since there are more people, more products, and just more going on in general, but the time I spend on that is a lot less than the time I used to spend on client work to make sure my salary got paid. Acquisitions can and should give you more opportunities to concentrate on what you are passionate about.&lt;/p&gt;
&lt;p&gt;Yes, it’s only been a month, how can I be sure this acquisition won’t suck? I feel like I’ve been working with these people for a long time, and in a way I have. I have been hanging out with them at conferences, working on open source code with them, and having conversations with them on Twitter for much longer than I’ve been their coworker.&lt;/p&gt;
&lt;p&gt;In the tech industry we have and should take advantage of those opportunities. We can follow and get to know people through their code (a great way to use &lt;a href=&quot;http://github.com/&quot;&gt;GitHub&lt;/a&gt;!) as well as on social networks and at conferences. Do your best to know the people you are getting into bed with.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/being-acquired-doesnt-have-to-suck/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Conclusion&lt;/h3&gt;
&lt;p&gt;My attitude towards acquisitions has definitely changed, but only because it’s clearer to me what works and what doesn’t.&lt;/p&gt;
&lt;p&gt;Avoid merging teams with drastically different cultures, understand the strengths and weaknesses of the teams on both sides and be committed to letting them do what they do best, and know the actual people you will share the future with.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Assimilating Contributed Code</title>
    <link href="https://jonmagic.com/posts/assimilating-contributed-code/"/>
    <updated>2011-12-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/assimilating-contributed-code/</id>
    <content type="html">&lt;p&gt;This year I authored several RubyGems and just this week finally learned how to work with a contributor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; &lt;a href=&quot;http://twitter.com/bryckbost&quot;&gt;@bryckbost&lt;/a&gt; points out that the &lt;a href=&quot;https://github.com/defunkt/github-gem&quot;&gt;github-gem&lt;/a&gt; does exactly what I wanted to do. See the &lt;strong&gt;Fetching and Evaluating Downstream Changes&lt;/strong&gt; section of the README.&lt;/p&gt;
&lt;p&gt;Of course &lt;a href=&quot;http://github.com/&quot;&gt;GitHub&lt;/a&gt; has the great &lt;strong&gt;Merge pull request&lt;/strong&gt; option when an auto-merge is possible, and I use that quite often, but the workflow on OSS projects sometimes requires you to run the tests locally and make any modifications before merging it.&lt;/p&gt;
&lt;p&gt;A quick search didn’t turn up any easy to read instructions, and I’m no git guru, so it took me a few minutes to figure out a simple workflow.&lt;/p&gt;
&lt;p&gt;Here is how I checked out, tested, modified, and merged a &lt;a href=&quot;https://github.com/jonmagic/ghee/pull/1&quot;&gt;massive pull request&lt;/a&gt; for &lt;a href=&quot;http://github.com/jonmagic/ghee&quot;&gt;Ghee&lt;/a&gt; from &lt;a href=&quot;https://github.com/rauhryan&quot;&gt;Ryan Rauh&lt;/a&gt; this week.&lt;/p&gt;
&lt;h3 id=&quot;1.-clone-my-repo-and-create-a-feature-branch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/assimilating-contributed-code/#1.-clone-my-repo-and-create-a-feature-branch&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; 1. Clone my repo and create a feature branch&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone git@github.com:jonmagic/ghee.git
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ghee
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout &lt;span class=&quot;token parameter variable&quot;&gt;-b&lt;/span&gt; repos_support master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a new branch called &lt;code&gt;repos_support&lt;/code&gt;, based off of &lt;code&gt;master&lt;/code&gt;, and checks it out.&lt;/p&gt;
&lt;h3 id=&quot;2.-pull-contributors-code-into-your-local-branch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/assimilating-contributed-code/#2.-pull-contributors-code-into-your-local-branch&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; 2. Pull contributors code into your local branch&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; pull https://github.com/rauhryan/ghee.git repos_support&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This pulls the &lt;code&gt;repos_support&lt;/code&gt; branch from the remote repo and merges it into the branch you have checked out (which we also called &lt;code&gt;repos_support&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;3.-run-tests%2C-make-modifications%2C-commit-changes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/assimilating-contributed-code/#3.-run-tests%2C-make-modifications%2C-commit-changes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; 3. Run tests, make modifications, commit changes&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;bundle &lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; rake
&lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; OHNOES.txt
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; OHNOES.txt
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Added OHNOES&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;4.-checkout-master%2C-merge-feature-branch%2C-push&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/assimilating-contributed-code/#4.-checkout-master%2C-merge-feature-branch%2C-push&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; 4. Checkout master, merge feature branch, push&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout master
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; merge repos_support
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/assimilating-contributed-code/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Conclusion&lt;/h3&gt;
&lt;p&gt;This workflow follows the &lt;a href=&quot;http://en.wikipedia.org/wiki/KISS_principle&quot;&gt;kiss principle&lt;/a&gt;, so it worked quite well for me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Please give me feedback.&lt;/strong&gt; I would love to hear about how other people accomplish this task, so I encourage you to leave links/tips/tricks in the comments below.&lt;/p&gt;
&lt;p&gt;Also be sure to checkout &lt;a href=&quot;https://github.com/jonmagic/ghee/compare/71fe16a34aad6edf9d17379e7f3dd413e6855e21...2065149ff01be1770d3d51bdb8b9272ebb972e4d&quot;&gt;Ryan’s awesome work&lt;/a&gt; on &lt;a href=&quot;http://github.com/jonmagic/ghee&quot;&gt;Ghee&lt;/a&gt;, a simple ruby client for the &lt;a href=&quot;http://developer.github.com/v3/&quot;&gt;GitHub API V3&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Twelve (gauge)</title>
    <link href="https://jonmagic.com/posts/twelve-gauge/"/>
    <updated>2011-12-09T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/twelve-gauge/</id>
    <content type="html">&lt;p&gt;Today I hacked together an easy to use gem for accessing the &lt;a href=&quot;http://get.gaug.es/&quot;&gt;Gauges&lt;/a&gt; API.&lt;/p&gt;
&lt;p&gt;When I started this morning 12-gauge was the first thing I thought, so I called the gem Twelve (silly I know).&lt;/p&gt;
&lt;p&gt;I had fun figuring out the API (with a little help from &lt;a href=&quot;http://twitter.com/bkeepers&quot;&gt;Brandon&lt;/a&gt;) and then writing the gem using some of the proxy object and method missing stuff I was learning a few weeks ago.&lt;/p&gt;
&lt;h3 id=&quot;installation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/twelve-gauge/#installation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Installation&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;gem &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; twelve&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;usage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/twelve-gauge/#usage&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Usage&lt;/h3&gt;
&lt;p&gt;Get the client ready:&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;access_token &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;abcd1234&quot;&lt;/span&gt;&lt;/span&gt;
bfg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Twelve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;access_token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Request your Gauges info:&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;bfg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;me&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For me I got this back:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;=&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Jonathan Hoyt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;urls&quot;&lt;/span&gt;=&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;self&quot;&lt;/span&gt;=&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://secure.gaug.es/me&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;gauges&quot;&lt;/span&gt;=&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://secure.gaug.es/gauges&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;clients&quot;&lt;/span&gt;=&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://secure.gaug.es/clients&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;=&gt;&lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;last_name&quot;&lt;/span&gt;=&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hoyt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;first_name&quot;&lt;/span&gt;=&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Jonathan&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt;=&gt;&lt;span class=&quot;token string&quot;&gt;&quot;jonmagic@gmail.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next try these:&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;bfg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clients
bfg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gauges&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;more-documentation-and-examples&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/twelve-gauge/#more-documentation-and-examples&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; More Documentation and Examples&lt;/h3&gt;
&lt;p&gt;It’s a full-fledged client, so you can create, update, and delete gauges as well as see all the different types of information available on a gauge. See the docs on &lt;a href=&quot;https://github.com/jonmagic/twelve&quot;&gt;GitHub&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>GitHubber</title>
    <link href="https://jonmagic.com/posts/githubber/"/>
    <updated>2011-12-05T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/githubber/</id>
    <content type="html">&lt;p&gt;Today the whole crew from Ordered List joins GitHub!&lt;/p&gt;
&lt;h3 id=&quot;ordered-list&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/githubber/#ordered-list&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Ordered List&lt;/h3&gt;
&lt;p&gt;Last year was a &lt;a href=&quot;https://jonmagic.com/blog/archives/2010/11/18/hey-mom-i-got-a-job/&quot;&gt;big year for myself&lt;/a&gt; and &lt;a href=&quot;http://orderedlist.com/&quot;&gt;Ordered List&lt;/a&gt;. &lt;a href=&quot;https://twitter.com/orderedlist&quot;&gt;Steve&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/jnunemaker&quot;&gt;John&lt;/a&gt; launched Harmony in August, I started hanging out with them on a regular basis and &lt;a href=&quot;https://jonmagic.com/blog/archives/2011/10/03/the-history-of-speaker-deck/&quot;&gt;began work&lt;/a&gt; on &lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt;, and the end of the year saw &lt;a href=&quot;http://opensoul.org/&quot;&gt;Brandon Keepers&lt;/a&gt; and I leaving our &lt;a href=&quot;http://collectiveidea.com/&quot;&gt;own&lt;/a&gt; &lt;a href=&quot;https://web.archive.org/web/2012/https://web.archive.org/web/2012/http://sabretechllc.com&quot;&gt;businesses&lt;/a&gt; to make OL &lt;a href=&quot;http://orderedlist.com/blog/articles/four/&quot;&gt;four strong&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This year was even bigger, launching &lt;a href=&quot;http://get.gaug.es/&quot;&gt;Gauges&lt;/a&gt; and &lt;a href=&quot;https://jonmagic.com/blog/archives/2011/10/10/launching-speaker-deck/&quot;&gt;Speaker Deck&lt;/a&gt;, adding &lt;a href=&quot;http://orderedlist.com/blog/articles/welcome-matt-graham/&quot;&gt;Matt Graham&lt;/a&gt; to the team, and beginning the journey of learning &lt;a href=&quot;https://jonmagic.com/blog/archives/2011/03/02/new-guy-blues/&quot;&gt;how&lt;/a&gt; to &lt;a href=&quot;https://jonmagic.com/blog/archives/2011/03/03/share-the-dream/&quot;&gt;work&lt;/a&gt; as a &lt;a href=&quot;https://jonmagic.com/blog/archives/2011/11/29/how-we-work/&quot;&gt;cohesive unit&lt;/a&gt;. While we learned each others strengths and weaknesses I began my own &lt;a href=&quot;https://jonmagic.com/blog/archives/2011/10/20/mentors/&quot;&gt;journey&lt;/a&gt; of becoming a full-time programmer that could not only contribute to the growth of our company, but also lead in certain circumstances.&lt;/p&gt;
&lt;p&gt;We all dreamed of taking over the world, and we knew we could do it together. We also know it takes time to build something great and that as time goes on new opportunities present themselves. Every once in awhile those opportunities get you even more excited than the dream you are currently living. One year (minus a day) after I joined Ordered List our entire team has accepted the opportunity to join &lt;a href=&quot;http://github.com/&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;github&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/githubber/#github&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; GitHub&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/about#company_description&quot;&gt;This company&lt;/a&gt; and the &lt;a href=&quot;https://github.com/about#the_team&quot;&gt;team behind it&lt;/a&gt; has been near and dear to our hearts for years. I had the chance to meet and hang out with a &lt;a href=&quot;http://zachholman.com/&quot;&gt;few&lt;/a&gt; &lt;a href=&quot;http://timclem.wordpress.com/&quot;&gt;GitHubbers&lt;/a&gt; &lt;a href=&quot;http://twitter.com/mtodd&quot;&gt;over&lt;/a&gt; the last year and have really come to appreciate them as &lt;a href=&quot;http://twitter.com/mtodd&quot;&gt;programmers&lt;/a&gt;, &lt;a href=&quot;http://tom.preston-werner.com/2011/03/29/ten-lessons-from-githubs-first-year.html&quot;&gt;professionals&lt;/a&gt;, &lt;a href=&quot;http://zachholman.com/posts/customer-support-doesnt-have-to-suck/&quot;&gt;writers&lt;/a&gt;, and people. When they started &lt;a href=&quot;http://speakerdeck.com/u/holman/p/how-github-uses-github-to-build-github&quot;&gt;talking&lt;/a&gt; &lt;a href=&quot;http://speakerdeck.com/u/schacon/p/robots-beer-and-maslow&quot;&gt;about&lt;/a&gt; their &lt;a href=&quot;http://speakerdeck.com/u/mojombo/p/optimizing-for-happiness&quot;&gt;culture&lt;/a&gt; at conferences I marveled even more, excited about how they were &lt;a href=&quot;http://speakerdeck.com/u/schacon/p/robots-beer-and-maslow?slide=79&quot;&gt;changing the rules&lt;/a&gt;, hiring &lt;a href=&quot;http://www.google.com/search?client=safari&amp;amp;rls=en&amp;amp;q=site:github.com/blog+is+a+GitHubber&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8&quot;&gt;tons of awesome people&lt;/a&gt;, and just &lt;a href=&quot;https://github.com/blog/936-one-million&quot;&gt;kicking-butt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When the opportunity to join GitHub materialized it sparked an epic discussion about the possibilities. It made sense in so many ways, but whenever you entertain the chance to change course you can’t help but wonder how far you can get on your current trajectory. There were a lot of factors to consider and in the end Steve and John decided that our personal and collective futures with GitHub seemed greater.&lt;/p&gt;
&lt;p&gt;Over the past few weeks the details were hammered out and during that time we’ve each had a chance to reset our dreams for the future, while trying to &lt;a href=&quot;http://twitter.com/michigangraham/status/142695650084139008&quot;&gt;keep&lt;/a&gt; &lt;a href=&quot;http://twitter.com/holman/status/142696256022659072&quot;&gt;the&lt;/a&gt; &lt;a href=&quot;http://twitter.com/michigangraham/status/143443710292672512&quot;&gt;whole&lt;/a&gt; &lt;a href=&quot;http://twitter.com/holman/status/143444127403618304&quot;&gt;thing&lt;/a&gt; a secret.&lt;/p&gt;
&lt;h3 id=&quot;the-future&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/githubber/#the-future&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Future&lt;/h3&gt;
&lt;p&gt;Right now I have no idea what the future holds, except that it is going to be great. I am most excited about the journey, learning new things, powering thru the hard times, accelerating during the good times, and building something that we can all be proud of.&lt;/p&gt;
&lt;p&gt;Thanks again to everyone involved in making this a reality. Watch out world.&lt;/p&gt;
&lt;h3 id=&quot;links&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/githubber/#links&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/blog/993-ordered-list-is-a-githubber&quot;&gt;Ordered List is a GitHubber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/blog/996-jonathan-hoyt-is-a-githubber&quot;&gt;Jonathan Hoyt is a GitHubber&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Finish Weekend</title>
    <link href="https://jonmagic.com/posts/finish-weekend/"/>
    <updated>2011-11-12T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/finish-weekend/</id>
    <content type="html">&lt;p&gt;While I initially had issues with the concept of Finish Weekend, I’m really glad I participated and believe everyone involved is better off for it.&lt;/p&gt;
&lt;h3 id=&quot;the-who&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/finish-weekend/#the-who&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Who&lt;/h3&gt;
&lt;p&gt;My friends at &lt;a href=&quot;http://collectiveidea.com/&quot;&gt;Collective Idea&lt;/a&gt; have apparently been talking about doing a Finish Weekend for a few years and this is the year they made it happen! They put out the word thru Twitter, friends, colleagues, and a ton of people signed up and showed up!&lt;/p&gt;
&lt;p&gt;I met folks from Detroit, Chicago, South Bend, and even as far away as California! There were programmers, designers, editors, math geeks, marketers, and testers just to name a few.&lt;/p&gt;
&lt;h3 id=&quot;the-why&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/finish-weekend/#the-why&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Why&lt;/h3&gt;
&lt;p&gt;Finish Weekend was born out of a personal and professional frustration with starting things and never finishing them. What if there was a weekend dedicated to taking something you’ve started, never found time to finish, and actually finish it. Even better, what if there were people around to help you finish it!&lt;/p&gt;
&lt;p&gt;Many folks showed up with projects to finish, but what really surprised me were how many people showed up to help other people finish! This brings us to my issue with Finish Weekend.&lt;/p&gt;
&lt;h3 id=&quot;my-issue&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/finish-weekend/#my-issue&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; My Issue&lt;/h3&gt;
&lt;p&gt;When first told about Finish Weekend immediately I reacted negatively because I believe we should be working hard to finish things every day. I love finishing things. Finishing projects is hard (that last 5% can be excruciating) but the joy you get from shipping feature X, or accomplishing goal Y, is greater than the joy I personally get from starting a project (as much fun as that is).&lt;/p&gt;
&lt;p&gt;When I finally got over myself and realized that Collective Idea was trying to help people learn how to finish things I signed up and made the trek to Holland, Michigan. I did not regret it.&lt;/p&gt;
&lt;h3 id=&quot;the-outcome&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/finish-weekend/#the-outcome&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Outcome&lt;/h3&gt;
&lt;p&gt;Today I saw a great group of people with greatly varying skillsets and backgrounds come together with one purpose, to finish things. We had people building video based web apps, crazy poetry recombinators, iPhone apps, and even a bond trader learning Python to automate a process that has taken him 1.5 hours every work evening for the last two years in Excel.&lt;/p&gt;
&lt;p&gt;I was able to teach basic programming concepts, performance measuring and optimization, even cut up a mockup into HTML/CSS, and paired with my coworker on some tech that will hopefully help power our products into the future.&lt;/p&gt;
&lt;p&gt;Collective Idea nailed it with Finish Weekend and my hope and desire is that we take the relationships and spirit of pitching in together to accomplish big and small things and carry it into the rest of our lives and not relegate it to a weekend.&lt;/p&gt;
&lt;p&gt;Of course we’ll need reminded every so often. See you at the next Finish Weekend 😃&lt;/p&gt;
&lt;h3 id=&quot;links&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/finish-weekend/#links&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Learn more about Finish Weekend at &lt;a href=&quot;http://finishweekend.com/&quot;&gt;finishweekend.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Learn more about the great folks at Collective Idea at &lt;a href=&quot;http://collectiveidea.com/&quot;&gt;collectiveidea.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>hubot Scripts Explained</title>
    <link href="https://jonmagic.com/posts/hubot-scripts-explained/"/>
    <updated>2011-10-28T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/hubot-scripts-explained/</id>
    <content type="html">&lt;p&gt;Ok, so now you’ve got your shiny new hubot up and ready to listen to your every command. But what should we tell him to do with our nonsense!&lt;/p&gt;
&lt;h3 id=&quot;basics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hubot-scripts-explained/#basics&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Basics&lt;/h3&gt;
&lt;p&gt;Scripts for &lt;a href=&quot;https://github.com/github/hubot&quot;&gt;hubot&lt;/a&gt; are written with &lt;a href=&quot;http://jashkenas.github.com/coffee-script/&quot;&gt;CoffeeScript&lt;/a&gt;. This is what a basic script looks like:&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# hubot greeting.&lt;/span&gt;
#
&lt;span class=&quot;token comment&quot;&gt;# (hi|hello) - say hi to your butler&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;robot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;respond &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;hi&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;hello&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Howdy!&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lets break this script down. The first line is just a description of the script. The third line tells hubot what to include in the help (when you ask hubot for help).&lt;/p&gt;
&lt;p&gt;The actual code starts on the module.exports line. Every script you make will start with that line.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;robot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next line tells hubot to respond to hi and hello.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;respond &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;hi&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;hello&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It uses a &lt;a href=&quot;http://en.wikipedia.org/wiki/Regular_expression&quot;&gt;regular expression&lt;/a&gt; to parse the text, looking for the words hi and hello. The i after the last slash tells the regular expression to not be case sensitive, so it will also match Hi and Hello.&lt;/p&gt;
&lt;p&gt;I like to use &lt;a href=&quot;http://rubular.com/&quot;&gt;rubular&lt;/a&gt; for writing and testing regular expressions. Its quick, easy to use, and while javascript regular expressions aren’t exactly like ruby regular expressions I haven’t run into any inconsistencies yet.&lt;/p&gt;
&lt;p&gt;Finally we tell hubot to take the message and send a message back.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Howdy!&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;respond-vs-hear&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hubot-scripts-explained/#respond-vs-hear&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Respond vs Hear&lt;/h3&gt;
&lt;p&gt;I didn’t discover this at first and thought that hubot only responded to commands directed at him, but then I discovered robot.hear! Whereas robot.respond only matches messages directed at hubot, robot.hear will run your regular expression against any chat message!&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Hubot has an attitude&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;robot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hear &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;tired&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;too hard&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;to hard&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;upset&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;bored&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Panzy&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See what I did there 😃 Any time someone in our chat room says they are tired, that something is too hard, upset, or bored, hubot tells them they’re a panzy. Oh yeah. This robot butler has an attitude.&lt;/p&gt;
&lt;h3 id=&quot;random&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hubot-scripts-explained/#random&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Random&lt;/h3&gt;
&lt;p&gt;I saw this used first in the shipit script, which displays a random shipit squirrel for your viewing pleasure whenever someone says the words “ship it” in your chat room.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Rodent Motivation&lt;/span&gt;
#
&lt;span class=&quot;token comment&quot;&gt;# ship it - Display a motivation squirrel&lt;/span&gt;
#

squirrels &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;/images/posts/hubot-scripts-explained/20100714-d6q52xajfh4cimxr3888yb77ru.jpg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;/images/posts/hubot-scripts-explained/20111026-r2wsngtu4jftwxmsytdke6arwd.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;/images/posts/hubot-scripts-explained/Screen_Shot_2011-10-27_at_9.36.45_AM.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;/images/posts/hubot-scripts-explained/squirrel.png&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;robot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hear &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;ship it&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random squirrels&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the array that we create with 4 different shipit squirrel images. Then notice this line:&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random squirrels&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The msg object has a random method on it which we can pass an array and it will pick a random item from that array! Super handy to keep things from getting repetitive.&lt;/p&gt;
&lt;h3 id=&quot;reply&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hubot-scripts-explained/#reply&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Reply&lt;/h3&gt;
&lt;p&gt;You can reply to a user by changing the send command to reply like this:&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reply &lt;span class=&quot;token string&quot;&gt;&quot;Why thank you sir!&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replies will be directed at a specific user, example: “@hoyt Why thank you sir!”&lt;/p&gt;
&lt;h3 id=&quot;http&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hubot-scripts-explained/#http&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Http&lt;/h3&gt;
&lt;p&gt;So far we’ve only talked about how to make hubot listen and respond in various ways. Hubot really starts to get interesting when we empower him to go out and do our bidding in the larger world though. This is where hubot really starts to become powerful!&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Whois for gems, because gem names are like domains in the 90&#39;s&lt;/span&gt;
#
&lt;span class=&quot;token comment&quot;&gt;# gem whois &amp;lt;gemname&gt; - returns gem details if it exists&lt;/span&gt;
#

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;robot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;respond &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;gem &lt;span class=&quot;token function&quot;&gt;whois&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    gemname &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;match&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;http://rubygems.org/api/v1/gems/&lt;span class=&quot;token interpolation variable&quot;&gt;#{gemname}&lt;/span&gt;.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
          json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;   gem name: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.name}&lt;/span&gt;&#92;n&#92;
     owners: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.authors}&lt;/span&gt;&#92;n&#92;
       info: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.info}&lt;/span&gt;&#92;n&#92;
    version: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.version}&lt;/span&gt;&#92;n&#92;
  downloads: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.downloads}&lt;/span&gt;&#92;n&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; error
          msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Gem not found. It will be mine. Oh yes. It will be mine. *sinister laugh*&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script is doing quite a bit so we’ll dissect it line by line.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;respond &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;gem &lt;span class=&quot;token function&quot;&gt;whois&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells hubot to look for messages directed at him that have the words “gem whois” and then some string.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;gemname &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;match&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I grab the gemname from the regular expression. msg.match with an integer will match the captured item from the regular expression. You use parenthesis to capture strings in regular expressions, and they get numbered left to right by however many there are. In this case its the first one, so we pass 1 to msg.match and then assign it off to our variable gemname.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;http://rubygems.org/api/v1/gems/&lt;span class=&quot;token interpolation variable&quot;&gt;#{gemname}&lt;/span&gt;.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we tell the msg.http object to use this url, with the gemname interpolated in it.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The .get() function kicks off the request and returns 3 objects, err, res, and body. In this case we’re only interested in body.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
  json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;   gem name: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.name}&lt;/span&gt;&#92;n&#92;
    owners: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.authors}&lt;/span&gt;&#92;n&#92;
    info: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.info}&lt;/span&gt;&#92;n&#92;
    version: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.version}&lt;/span&gt;&#92;n&#92;
    downloads: &lt;span class=&quot;token interpolation variable&quot;&gt;#{json.downloads}&lt;/span&gt;&#92;n&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; error
  msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Gem not found. It will be mine. Oh yes. It will be mine. *sinister laugh*&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If JSON.parse is able to parse the body then it displays the gem information, if it errors we get the “Gem not found” message.&lt;/p&gt;
&lt;h3 id=&quot;advanced-http&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hubot-scripts-explained/#advanced-http&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Advanced HTTP&lt;/h3&gt;
&lt;p&gt;What if you want to hit an API that requires authentication? Here is a script that uses http basic auth when hitting the &lt;a href=&quot;http://dnsimple.com/&quot;&gt;dnsimple&lt;/a&gt; api to check domain name availability.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Domain availability via DNSimple, requires you set&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# DNSIMPLE_USERNAME &amp;amp; DNSIMPLE_PASSWORD environment variables&lt;/span&gt;
#
&lt;span class=&quot;token comment&quot;&gt;# check domain &amp;lt;domainname&gt; - returns whether a domain is available&lt;/span&gt;
#

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;robot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  robot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hear &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;check &lt;span class=&quot;token function&quot;&gt;domain&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    domain &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;match&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DNSIMPLE_USERNAME&lt;/span&gt;
    pass &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DNSIMPLE_PASSWORD&lt;/span&gt;
    auth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Basic &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;:&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; pass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;base64&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://dnsimple.com/domains/&lt;span class=&quot;token interpolation variable&quot;&gt;#{domain}&lt;/span&gt;/check&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;Authorization&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; auth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;Accept&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;application/json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;statusCode
          &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;
            msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Sorry, &lt;span class=&quot;token interpolation variable&quot;&gt;#{domain}&lt;/span&gt; is not available.&quot;&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;
            msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Cybersquat that s***!&quot;&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;401&lt;/span&gt;
            msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;You need to authenticate by setting the DNSIMPLE_USERNAME &amp;amp; DNSIMPLE_PASSWORD environment variables&quot;&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
            msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Unable to process your request and we&#39;re not sure why :(&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We do the same thing as the last example, grabbing the domain name that is captured by the regular expression, but then things get a bit different.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DNSIMPLE_USERNAME&lt;/span&gt;
pass &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DNSIMPLE_PASSWORD&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we grab some environment variables and assign them to variables. If you are &lt;a href=&quot;http://jonmagic.com/blog/archives/2011/10/28/hipchat-hubot-and-me/&quot;&gt;deploying hubot to Heroku&lt;/a&gt; then setting environment variables is crazy easy:&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;heroku &lt;span class=&quot;token property&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;add &lt;span class=&quot;token constant&quot;&gt;DNSIMPLE_USERNAME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;john&lt;span class=&quot;token class-member variable&quot;&gt;@doe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;com &lt;span class=&quot;token constant&quot;&gt;DNSIMPLE_PASSWORD&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;4w3s0m3p4ssw0rd&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we have to create the auth string that we’ll stuff into the authorization header.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;auth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Basic &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;:&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; pass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;base64&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating that auth string is some javascript voodoo that took me awhile to figure out, finally finding an article on &lt;a href=&quot;http://stackoverflow.com/questions/3905126/how-to-use-http-client-in-node-js-if-there-are-basic-authorization&quot;&gt;stackoverflow&lt;/a&gt; that had the magic I needed.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://dnsimple.com/domains/&lt;span class=&quot;token interpolation variable&quot;&gt;#{domain}&lt;/span&gt;/check&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;Authorization&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; auth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;Accept&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;application/json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The really interesting line in the code above is the .headers() line. We can set headers for the http request before calling .get(), allowing us to configure the Authorization and Accept headers! Now the last bit.&lt;/p&gt;
&lt;pre class=&quot;language-coffeescript&quot;&gt;&lt;code class=&quot;language-coffeescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;statusCode
  &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;
    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Sorry, &lt;span class=&quot;token interpolation variable&quot;&gt;#{domain}&lt;/span&gt; is not available.&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;
    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Cybersquat that s***!&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;401&lt;/span&gt;
    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;You need to authenticate by setting the DNSIMPLE_USERNAME &amp;amp; DNSIMPLE_PASSWORD environment variables&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;send &lt;span class=&quot;token string&quot;&gt;&quot;Unable to process your request and we&#39;re not sure why :(&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The response (res) object has a statusCode method on it which we can use to match http response codes. Based on the dnsimple api I was able to make a simple switch statement with the correct replies for each status code.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hubot-scripts-explained/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Conclusion&lt;/h3&gt;
&lt;p&gt;I hope this is helpful to some folks out there. I can’t wait to see what other hubot scripts people write!&lt;/p&gt;
&lt;p&gt;Make sure to fork the &lt;a href=&quot;https://github.com/github/hubot-scripts&quot;&gt;hubot-scripts&lt;/a&gt; repo, add your scripts, and do a pull request once you’ve got them working. The gem whois and dnsimple scripts above have already been accepted into the hubot-scripts library!&lt;/p&gt;
&lt;p&gt;Enjoy 😃&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>HipChat, hubot, and Me</title>
    <link href="https://jonmagic.com/posts/hipchat-hubot-and-me/"/>
    <updated>2011-10-28T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/hipchat-hubot-and-me/</id>
    <content type="html">&lt;p&gt;How you can give Siri her very own robot brother with some help from Heroku and HipChat.&lt;/p&gt;
&lt;p&gt;Github released &lt;a href=&quot;https://github.com/github/hubot&quot;&gt;hubot&lt;/a&gt; this week and geeks the world over have been transfixed by his awesomeness. He’s the second robot butler to enter my life lately, &lt;a href=&quot;http://www.apple.com/iphone/features/siri.html&quot;&gt;Siri&lt;/a&gt; being the first. Together these two fulfill my every wish (not quite) and are at my beck and call day and night (too true).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE: for a slightly different take &lt;a href=&quot;http://martinciu.com/2011/11/deploying-hubot-to-heroku-like-a-boss.html&quot;&gt;try these instructions by @martinciu&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE: to learn more about writing hubot scripts &lt;a href=&quot;http://jonmagic.com/blog/archives/2011/10/28/hubot-scripts-explained/&quot;&gt;read this&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hipchat-hubot-and-me/#getting-started&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Getting Started&lt;/h3&gt;
&lt;p&gt;The first step is to head on over to the &lt;a href=&quot;https://github.com/github/hubot/downloads&quot;&gt;hubot downloads&lt;/a&gt; to grab yourself a copy of the latest hubot tarball. Download it and then open your command line to your download folder. It looked something like this for me:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; Downloads
&lt;span class=&quot;token function&quot;&gt;tar&lt;/span&gt; zxvf hubot-1.1.3.tar.gz
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; hubot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure you have node.js and npm installed. I used &lt;a href=&quot;http://mxcl.github.com/homebrew/&quot;&gt;homebrew&lt;/a&gt; to accomplish this.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt;
brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you can just run the hubot binary and it should install all the necessary packages and fire right up.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;bin/hubot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you run into any issues at this point please consult the &lt;a href=&quot;https://github.com/github/hubot/issues&quot;&gt;hubot Issues&lt;/a&gt; page on Github, because someone has probably already run into the issue.&lt;/p&gt;
&lt;h3 id=&quot;configuring-heroku-and-hipchat&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hipchat-hubot-and-me/#configuring-heroku-and-hipchat&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Configuring Heroku and HipChat&lt;/h3&gt;
&lt;p&gt;First we need to initialize git for our hubot so he’s actually stored in version control.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; init &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;spawning my first robot!&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we create a new instance on the &lt;a href=&quot;http://devcenter.heroku.com/articles/cedar&quot;&gt;Heroku cedar stack&lt;/a&gt; (assuming you already are &lt;a href=&quot;http://devcenter.heroku.com/articles/quickstart&quot;&gt;setup to use Heroku&lt;/a&gt;).&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;heroku create my_hubot_app_name &lt;span class=&quot;token parameter variable&quot;&gt;--stack&lt;/span&gt; cedar&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we need to setup hubot and Heroku to connect to our &lt;a href=&quot;http://hipchat.com/&quot;&gt;HipChat&lt;/a&gt; account.&lt;/p&gt;
&lt;p&gt;This requires creating the user in HipChat and then going to your account page in HipChat (&lt;a href=&quot;https://mycompanyhere.hipchat.com/account/xmpp&quot;&gt;https://mycompanyhere.hipchat.com/account/xmpp&lt;/a&gt;) to get some values that we’ll need for configuring Heroku.&lt;/p&gt;
&lt;p&gt;You’ll also need to go to the Group Admin in HipChat and the API tab to create an API Auth Token. Run the following commands replacing the values with the ones that match in the HipChat settings:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;heroku config:add &lt;span class=&quot;token assign-left variable&quot;&gt;HUBOT_HIPCHAT_JID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Username&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

heroku config:add &lt;span class=&quot;token assign-left variable&quot;&gt;HUBOT_HIPCHAT_NAME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Room nickname&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# example: heroku config:add HUBOT_HIPCHAT_NAME=&quot;Geoffrey Butler&quot;&lt;/span&gt;

heroku config:add &lt;span class=&quot;token assign-left variable&quot;&gt;HUBOT_HIPCHAT_PASSWORD&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Password you created &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; hubots user&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
heroku config:add &lt;span class=&quot;token assign-left variable&quot;&gt;HUBOT_HIPCHAT_TOKEN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Token from Group Admin and API&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need to add the RedisToGo addon. (Thanks to &lt;a href=&quot;http://profitably.com/&quot;&gt;Graham Siener&lt;/a&gt; for pointing this out)&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;heroku addons:add redistogo:nano&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that Heroku is configured we need to slightly modify our Procfile to use the right adapter and name. Mine looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;app: bin/hubot &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; hipchat &lt;span class=&quot;token parameter variable&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Geoffrey Butler&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace Geoffrey Butler with whatever you named the user in HipChat. This should exactly match the Room nickname we set above. Once you’ve updated the Procfile and saved it we need to commit it with git.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; Procfile
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;updated Procfile to use hipchat adapter and hipchat room nickname&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;deploying-to-heroku&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/hipchat-hubot-and-me/#deploying-to-heroku&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Deploying to Heroku&lt;/h3&gt;
&lt;p&gt;Now we should be ready to deploy.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git push heroku master
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This step failed for me at first. I had to edit package.json and change the dependencies section to look like this:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;hubot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.1.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;hubot-scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.1.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;optparse&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.0.1&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The latest version of hubot-scripts blows up on the Heroku Cedar stack unfortunately. So after this step I committed my changes one more time and deployed.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; package.json
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;changed dependencies&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push heroku master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Woot! It worked! Now that its deployed we just need to start it up.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;heroku ps:scale &lt;span class=&quot;token assign-left variable&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside our HipChat rooms Geoffrey suddenly appeared and I was able to talk to him.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@geoffrey help
(thanks|thank you) - say thanks to your butler
&amp;lt;keyword&amp;gt; tweet - Returns a link to a tweet about &amp;lt;keyword&amp;gt;
&amp;lt;user&amp;gt; is a badass guitarist - assign a role to a user
&amp;lt;user&amp;gt; is not a badass guitarist - remove a role from a user
animate me &amp;lt;query&amp;gt;  - The same thing as `image me`, except adds a few
ascii me &amp;lt;text&amp;gt; - Show text in ascii art.
check domain &amp;lt;domainname&amp;gt; - returns whether a domain is available
convert me &amp;lt;expression&amp;gt; to &amp;lt;units&amp;gt; - Convert expression to given units.
gem whois &amp;lt;gemname&amp;gt; - returns gem details if it exists
haters - Returns a random haters gonna hate url
help - Displays all of the help commands that Hubot knows about.
image me &amp;lt;query&amp;gt;    - The Original. Queries Google Images for &amp;lt;query&amp;gt; and
map me &amp;lt;query&amp;gt; - Returns a map view of the area returned by `query`.
math me &amp;lt;expression&amp;gt; - Calculate the given expression.
mustache me &amp;lt;query&amp;gt; - Searches Google Images for the specified query and
mustache me &amp;lt;url&amp;gt;   - Adds a mustache to the specified URL.
remind me in &amp;lt;time&amp;gt; to &amp;lt;action&amp;gt;    - Set a reminder in &amp;lt;time&amp;gt; to do an &amp;lt;action&amp;gt;
ship it - Display a motivation squirrel
show storage - Display the contents that are persisted in redis
show users - Display all users that hubot knows about
translate me &amp;lt;phrase&amp;gt; - Searches for a translation for the &amp;lt;phrase&amp;gt; and then
translate me from &amp;lt;source&amp;gt; into &amp;lt;target&amp;gt; &amp;lt;phrase&amp;gt; - Translates &amp;lt;phrase&amp;gt; from &amp;lt;source&amp;gt; into &amp;lt;target&amp;gt;. Both &amp;lt;source&amp;gt; and &amp;lt;target&amp;gt; are optional
who is &amp;lt;user&amp;gt; - see what roles a user has
youtube me &amp;lt;query&amp;gt; - Searches YouTube for the query and returns the video
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Awesome! Enjoy 😃&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Mentors</title>
    <link href="https://jonmagic.com/posts/mentors/"/>
    <updated>2011-10-20T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/mentors/</id>
    <content type="html">&lt;p&gt;We need more mentors. Mentors help us avoid mistakes and give us guidance on how to be better at our jobs and at life.&lt;/p&gt;
&lt;h3 id=&quot;my-mentors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/mentors/#my-mentors&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; My Mentors&lt;/h3&gt;
&lt;p&gt;The first eight months of my new job at &lt;a href=&quot;http://orderedlist.com/&quot;&gt;Ordered List&lt;/a&gt; I paired with my coworker &lt;a href=&quot;http://twitter.com/bkeepers&quot;&gt;Brandon&lt;/a&gt; three or four days a week. We kept each other on task, but most important for me, he started teaching me the process of writing beautiful and maintainable code. He had years of experience in this industry and a passion for elegant solutions that I didn’t have, but I could learn from him.&lt;/p&gt;
&lt;p&gt;While we aren’t pairing as often now, Brandon and I have built a level of trust that enables us to quickly and easily share ideas and continue to educate each other and make better software.&lt;/p&gt;
&lt;p&gt;In the last couple months my coworker/boss &lt;a href=&quot;http://twitter.com/jnunemaker&quot;&gt;John&lt;/a&gt; has been mentoring me. We meet once a week, either over breakfast, lunch, or just a hot chocolate, and have a nice long chat. We usually cover things we’ve been thinking about the past week, what to focus on in the next week or month, personal goals, even our personal lives. This too has been invaluable for me.&lt;/p&gt;
&lt;h3 id=&quot;why-mentors-matter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/mentors/#why-mentors-matter&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Why Mentors Matter&lt;/h3&gt;
&lt;p&gt;In my time with both Brandon and John I’ve been able to get someone else’s perspective on how I’m progressing as both a programmer and a person. Looking back I’m completely shocked by how much I’ve changed for the better thanks to them taking the time to care about me and give me feedback that I can act on.&lt;/p&gt;
&lt;p&gt;By listening to their advice, which has years of experience and thought behind it, I am able to set a better course for my own life. A good mentor shares what has worked and what has not.&lt;/p&gt;
&lt;h3 id=&quot;finding-a-mentor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/mentors/#finding-a-mentor&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Finding A Mentor&lt;/h3&gt;
&lt;p&gt;If you have the opportunity to be mentored right now, by someone you respect, seize it. Good mentors are few and far between in my experience. In my current situation I didn’t have to go seeking a mentor, they came to me and offered to help.&lt;/p&gt;
&lt;p&gt;In the past I have had to seek out mentors. I wouldn’t be working at Ordered List if I hadn’t reached out four years ago, initially seeking like minded geeks, but eventually finding &lt;a href=&quot;http://twitter.com/orderedlist&quot;&gt;Steve&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/jnunemaker&quot;&gt;John&lt;/a&gt; and growing to respect them, so much so that I took advantage of every opportunity to hang out and learn from them.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/mentors/#final-thoughts&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Final Thoughts&lt;/h3&gt;
&lt;p&gt;While having a good mentor can be uplifting, constructive, and life changing, likewise a bad mentor can tear you down. Be careful entering a mentoring relationship to ensure the mentor is someone you have at least some level of trust and respect for. If you leave a meeting challenged and excited, things are probably on the right track. If you leave a meeting discouraged and ready to quit, examine whether its your attitude that is the problem or whether you can’t trust and respect your mentor enough to learn.&lt;/p&gt;
&lt;p&gt;One on one time with your mentor is essential, so put it on the calendar and stick to it. If you aren’t serious enough to make the meeting happen then figure out why you are resistant and fix it. John and I have to reschedule a meeting every so often, but we try to avoid canceling.&lt;/p&gt;
&lt;p&gt;Finally I would just like to encourage you to mentor someone yourself, if you are ready. I am not mentoring anyone at the moment, but I have in the past and I will in the future.&lt;/p&gt;
&lt;p&gt;We need more mentors.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Why Should We Write?</title>
    <link href="https://jonmagic.com/posts/why-should-we-write/"/>
    <updated>2011-10-14T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/why-should-we-write/</id>
    <content type="html">&lt;p&gt;Building a career as a programmer requires a lot of hard work, determination, and in my opinion a lot of writing.&lt;/p&gt;
&lt;p&gt;How do you build a personal brand online? How do you get opportunities to work on awesome projects? How do you get invited to speak at conferences? Looking at my coworkers’ success I would deduce that you have to work hard on stuff you care about and then share the knowledge you have gained with your peers, writing on a &lt;a href=&quot;http://orderedlist.com/blog/&quot;&gt;blog&lt;/a&gt; &lt;a href=&quot;http://railstips.org/&quot;&gt;for&lt;/a&gt; &lt;a href=&quot;http://opensoul.org/&quot;&gt;example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Writing has always been a struggle for me, I was always a math geek, but I cannot use that as an excuse if I want to continually advance my career. If we are working online, building websites, doing design, programming web applications, or working on infrastructure, we need to be writing about our experiences.&lt;/p&gt;
&lt;p&gt;We run into new problems every day. More often than not the solution is a &lt;a href=&quot;http://www.google.com/search?client=safari&amp;amp;rls=en&amp;amp;q=what+is+the+answer+to+life+the+universe+and+everything&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8&quot;&gt;Google search&lt;/a&gt; away. But when it isn’t and we find a solution on our own, we should be writing it down and sharing it with the world.&lt;/p&gt;
&lt;p&gt;Whether it’s writing &lt;a href=&quot;https://github.com/jonmagic/grim#readme&quot;&gt;readme’s&lt;/a&gt; for an open source library, &lt;a href=&quot;http://jonmagic.com/blog/archives/2011/10/06/grim-multiprocessor-to-the-rescue/&quot;&gt;blogging&lt;/a&gt; about how you solved a problem, or &lt;a href=&quot;http://jonmagic.com/blog/archives/2011/10/03/just-write-it-down/&quot;&gt;sharing some insight&lt;/a&gt; about how to become a better person, I think we should all be writing more and sharing it with the world.&lt;/p&gt;
&lt;p&gt;Let’s become better communicators thru practice, making the world a better place while at the same time advancing our careers.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Launching Speaker Deck</title>
    <link href="https://jonmagic.com/posts/launching-speaker-deck/"/>
    <updated>2011-10-10T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/launching-speaker-deck/</id>
    <content type="html">&lt;p&gt;Looking back at the last two weeks since launching Speaker Deck.&lt;/p&gt;
&lt;h3 id=&quot;launching&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/launching-speaker-deck/#launching&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Launching&lt;/h3&gt;
&lt;p&gt;Knowing when to launch a product is a painstaking task and ultimately you are never sure if it’s the right time, but at some point you have to pull the trigger. September 26th &lt;a href=&quot;http://orderedlist.com/the-team/&quot;&gt;we&lt;/a&gt; finally committed and launched &lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; to the world.&lt;/p&gt;
&lt;p&gt;The past two weeks since launch have been pretty intense, we’ve had over 2500 signups and over 1000 presentations uploaded. We’ve received hundreds of emails, people just telling us how excited they are about Speaker Deck and many of them asking for a feature or requesting help. Seeing everyone’s reactions has confirmed in our minds that we weren’t the only ones feeling severe slide hosting pain.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://twitter.com/#!/search/speakerdeck&quot;&gt;twitter search for speakerdeck&lt;/a&gt; has seen a constant stream of tweets, almost all of them linking directly to specific slide decks, which is awesome!&lt;/p&gt;
&lt;h3 id=&quot;fixing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/launching-speaker-deck/#fixing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Fixing&lt;/h3&gt;
&lt;p&gt;Thankfully &lt;a href=&quot;http://heroku.com/&quot;&gt;Heroku&lt;/a&gt; has been a fantastic platform for Speaker Deck so far. During peak traffic we’ve been able to easily scale up both our web capacity (how many requests we can handle from your browsers) and the background worker capacity (where we process your PDFs into individual slides).&lt;/p&gt;
&lt;p&gt;No story is complete without some drama though, right? When we opened up signups we almost immediately began seeing presentations that wouldn’t process. Thankfully within a week we were able to &lt;a href=&quot;http://jonmagic.com/blog/archives/2011/10/06/grim-multiprocessor-to-the-rescue/&quot;&gt;roll out fixes&lt;/a&gt; that got us past this hurdle.&lt;/p&gt;
&lt;p&gt;We also ran into problems with slides acting like they were never processed even though they had. This turned out to be race conditions. In addition, there were issues with caching. There were a couple instances where we cached something and then missed clearing that item from the cache when the item was updated. Hard bugs to track down but easy to fix thankfully.&lt;/p&gt;
&lt;p&gt;All in all things went really well, thankfully, since we were all gone to New Orleans for &lt;a href=&quot;http://rubyconf.org/&quot;&gt;RubyConf&lt;/a&gt; and without good internet. Looking back, launching 2 days before a road trip was probably not the wisest thing we’ve ever done.&lt;/p&gt;
&lt;h3 id=&quot;future&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/launching-speaker-deck/#future&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Future&lt;/h3&gt;
&lt;p&gt;I’m betting many of you are thinking “how the heck is this sustainable?” I’ll let you know when we figure it out. Seriously though, we do have plans to monetize and I’d like to start talking about them to see what you folks think.&lt;/p&gt;
&lt;p&gt;The first idea is just what we’re doing right now, mentioning our other products (&lt;a href=&quot;http://get.gaug.es/&quot;&gt;Gauges&lt;/a&gt; &amp;amp; Harmony) in a very small and tasteful way in the sidebar. For this plan to succeed on its own there would have to be a lot of people clicking through and signing up for our other products.&lt;/p&gt;
&lt;p&gt;The second plan is to add pro accounts. We’ve heard a lot of great feedback about bigger features people want, like private presentations that you can share with a select group and also statistics. We’d love to hear more about features you want, especially the ones you’d be willing to pay for.&lt;/p&gt;
&lt;p&gt;We of course still have a lot of core features to build, like search, full screen mode, following presenters, activity streams, and so much more.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/launching-speaker-deck/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Conclusion&lt;/h3&gt;
&lt;p&gt;All of us at Ordered List just want to say thanks. It has been a wild ride and we’ve been blown away by how many people are using Speaker Deck and all the good will that has been coming our way. Thank you for making it a success!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Grim MultiProcessor to the Rescue!</title>
    <link href="https://jonmagic.com/posts/grim-multiprocessor-to-the-rescue/"/>
    <updated>2011-10-06T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/grim-multiprocessor-to-the-rescue/</id>
    <content type="html">&lt;p&gt;We recently ran into issues with certain versions of GhostScript not being able to convert PDFs into images. Here’s how we solved the problem.&lt;/p&gt;
&lt;h3 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/grim-multiprocessor-to-the-rescue/#the-problem&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Problem&lt;/h3&gt;
&lt;p&gt;Last week we launched &lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; and since launch over 2000 people have signed up and uploaded almost a 1000 presentations. We were using GhostScript 9.04 because it is faster than 9.02 by a factor of two and fixed some processing problems we had experienced converting certain PDFs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;convert: Postscript delegate failed `presentation.pdf&#39;: No such file or directory @ error/pdf.c/ReadPDFImage/663.
convert: missing an image filename `slide.jpg&#39; @ error/convert.c/ConvertImageCommand/3011.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately we ran into the same processing issue with 9.04 and through trial and error figured out that those presentations that wouldn’t process with 9.04 would process with 9.02. So what to do! GhostScript 9.04 works for most presentations and is faster but fails on certain PDFs where 9.02 actually does work.&lt;/p&gt;
&lt;h3 id=&quot;the-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/grim-multiprocessor-to-the-rescue/#the-solution&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Solution&lt;/h3&gt;
&lt;p&gt;We are using &lt;a href=&quot;http://jonmagic.com/blog/archives/2011/09/06/grim/&quot;&gt;Grim&lt;/a&gt; to convert PDFs into images, so I decided that Grim needed to be updated to support multiple processors. Better yet I thought it would be cool if Grim could automatically try multiple processors if you specified more than one, starting with the first and falling back to secondary processors as needed.&lt;/p&gt;
&lt;p&gt;I started working on adding Processors to Grim while at &lt;a href=&quot;http://rubyconf.org/&quot;&gt;RubyConf&lt;/a&gt; and Monday finished up getting it all working. I started by pulling out the ImageMagick and GhostScript specific code into an ImageMagickProcessor class that lets you pass in the path to convert and gs (ImageMagick and GhostScript executables).&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;Grim&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;processor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Grim&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ImageMagickProcessor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:imagemagick_path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/path/to/convert&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:ghostscript_path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/path/to/gs&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once I had that working (super easy thanks to a great test suite!) I started in on the MultiProcessor.&lt;/p&gt;
&lt;p&gt;The MultiProcessor accepts an array of processors and uses them in order, falling back to secondary processors when the first in line fails. If none of them succeed it just raises the same error the processors on their own raise.&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;Grim&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;processor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Grim&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MultiProcessor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  Grim&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ImageMagickProcessor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:imagemagick_path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/path/to/6.7/convert&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:ghostscript_path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/path/to/9.04/gs&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Grim&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ImageMagickProcessor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:imagemagick_path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/path/to/6.6/convert&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:ghostscript_path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/path/to/9.02/gs&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Monday we deployed &lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; with the updated Grim gem and reprocessed the 13 presentations that were stuck. Every single one of them processed without a hitch!&lt;/p&gt;
&lt;h3 id=&quot;the-future&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/grim-multiprocessor-to-the-rescue/#the-future&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Future&lt;/h3&gt;
&lt;p&gt;Now that the actual processing logic has been split out into easy to build Processor classes, I see us building more processors for Grim. Why not a Quartz processor, or a processor that works on Windows.&lt;/p&gt;
&lt;p&gt;If you would like to use Grim in your project or get involved with development just head over to the &lt;a href=&quot;http://github.com/jonmagic/grim&quot;&gt;Grim repo on Github&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Thank You Steve Jobs</title>
    <link href="https://jonmagic.com/posts/thank-you-steve-jobs/"/>
    <updated>2011-10-05T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/thank-you-steve-jobs/</id>
    <content type="html">&lt;p&gt;When did you start using a Mac? Just wanted to share my story and how Steve Jobs and Apple changed my life.&lt;/p&gt;
&lt;p&gt;I bought my first Apple laptop, the 12” Powerbook, in 2002 for $2000. It forever changed my life. Simple, intuitive, and extremely powerful.&lt;/p&gt;
&lt;p&gt;Before that I had only ever owned PCs, my first one a 286SX my parents bought in 1987. Before that I had played on 8088’s, playing Frogger and learning a little BASIC.&lt;/p&gt;
&lt;p&gt;In the 90’s my uncle John would drop off computer parts at my house and I built many computers, even entering a 386SX in the 4H county fair when I was 10. I won every award you could win by default, not many other 10 year olds were entering computers in the 4H. Not sure if they ever have since in Hillsdale, Michigan.&lt;/p&gt;
&lt;p&gt;I remember my first experience with an Apple. There was room full of Apple IIe’s at Kimball Camp in Reading, Michigan. I remember not being impressed, as they were pretty far behind what I was using at the time (486 running Windows 3.1).&lt;/p&gt;
&lt;p&gt;Then in the mid 90’s I started using Macs running OS 7 or 8 at Spring Arbor College where my mom went to finish her bachelors. I was impressed even then by the interface, it was just easier to use. But I continued to use PCs for years, becoming a PC technician, and fixing computers and training people how to use them through high school and into college.&lt;/p&gt;
&lt;p&gt;Then during my junior year of college (2002) I finally drank the kool-aid and switched to a Mac. I had just purchased a brand new HP and was hanging out with my friend Christian (&lt;a href=&quot;http://twitter.com/mintchaos&quot;&gt;@mintchaos&lt;/a&gt;), who had been a Mac user for life, and noticed how much faster and easier to use his white iBook was. I played with it a bit and the next day returned the HP and bought myself a Mac.&lt;/p&gt;
&lt;p&gt;My first Apple computer was the 12” PowerBook. It was awesome. OS X, the PowerBook hardware, and the Apple culture became part of who I was.&lt;/p&gt;
&lt;p&gt;I had spent years spending the majority of my time keeping my computers running, keeping my friends, family, and clients’ computers running. Suddenly I found out there was a computer that you could just use to get stuff done, real stuff, like building websites, programming, graphic design, building cool stuff out of photos and video, and the barrier to entry was only a slightly premium price. The learning curve was extremely low, the interface crazy intuitive, and it never crashed!&lt;/p&gt;
&lt;p&gt;When clients asked what kind of computer I used I was always excited to tell them about Apple. I would usually say something like, “I fix computers all day everyday, I use an Apple at home because it just works.”&lt;/p&gt;
&lt;p&gt;Fast forward nine years and I am absolutely convinced that Steve Jobs and what he built at Apple were and are the single most important influences on my technological life and career.&lt;/p&gt;
&lt;p&gt;I am now a software developer, using my Mac and iPhone every day for fun, work, communication, and so much more. I can’t imagine I would have ever accomplished so much in the last nine years if it weren’t for Apple.&lt;/p&gt;
&lt;p&gt;I just finished reading &lt;em&gt;iWoz&lt;/em&gt; and I’m really looking forward to reading Jobs’s biography.&lt;/p&gt;
&lt;p&gt;I owe a debt of gratitude to Steve. My thoughts and prayers go out to his friends and family.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The History of Speaker Deck</title>
    <link href="https://jonmagic.com/posts/the-history-of-speaker-deck/"/>
    <updated>2011-10-03T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/the-history-of-speaker-deck/</id>
    <content type="html">&lt;p&gt;How a product was born, from inception to implementation, and distractions to launch.&lt;/p&gt;
&lt;h3 id=&quot;inception&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/the-history-of-speaker-deck/#inception&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Inception&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; was born in a little Irish bar right around the corner from our offices in South Bend Indiana in May of&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I was meeting &lt;a href=&quot;http://orderedlist.com/the-team/#steve-smith&quot;&gt;Steve&lt;/a&gt; and &lt;a href=&quot;http://orderedlist.com/the-team/john-nunemaker&quot;&gt;John&lt;/a&gt; for lunch and they were talking about how much they disliked the slide sharing options currently available. It was of special interest to them as they do a lot of public speaking and at the time were teaching classes at &lt;a href=&quot;http://nd.edu/&quot;&gt;Notre Dame&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;They were dreaming (as they do) of a better way to share presentations with the world. Something elegant, simple, without all the mess. Then reality hit and they realized they just didn’t have the time to build it. Life was too busy, family, client work, teaching, and Harmony ate up all their time, there was just no way they could start working on a new product.&lt;/p&gt;
&lt;h3 id=&quot;implementation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/the-history-of-speaker-deck/#implementation&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Implementation&lt;/h3&gt;
&lt;p&gt;This was my opportunity. If I was serious about my dream of becoming a programmer, here was my chance. I said “I’ll do it”, then cracked open my laptop and started hacking around with ghostscript and imagemagick to see if I could extract images from pdf’s. An hour later the core tech (&lt;a href=&quot;http://github.com/jonmagic/grim&quot;&gt;now extracted into a rubygem&lt;/a&gt;) behind Speaker Deck was working (in a limited fashion) and a product was born.&lt;/p&gt;
&lt;p&gt;June 1st of 2010 was my first git commit, a basic rails app with an already processed presentation so I had images to use as I created the html and css from Steve’s initial mockups. It quickly took on a life of its own at that point, Steve implementing an awesome embeddable slide viewer, so nifty we actually use it on Speaker Deck the same exact way you use it when embedding a presentation on your own site.&lt;/p&gt;
&lt;p&gt;The guys taught me test driven development while building Speaker Deck, and over the summer and into the fall I kept working on it. Initially just Steve and John were using it to host their slides, but then an opportunity arose while at &lt;a href=&quot;http://www.10gen.com/events/mongo-chicago-2010&quot;&gt;Mongo Chicago&lt;/a&gt;, and on October 20th of 2010 we had our first beta testers signup and upload presentations!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/johnnunemaker/4609508175/in/photostream/&quot;&gt;&lt;img src=&quot;https://jonmagic.com/images/posts/the-history-of-speaker-deck/4609508175_f3bcf70e45_b.jpg&quot; alt=&quot;John presenting at Mongo Chicago 2010&quot; /&gt;&lt;/a&gt;
(my coworker/boss John presenting at Mongo Chicago 2010)&lt;/p&gt;
&lt;h3 id=&quot;good-distractions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/the-history-of-speaker-deck/#good-distractions&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Good Distractions&lt;/h3&gt;
&lt;p&gt;Almost a year has passed since we started signing up our first beta users and September 26th we launched Speaker Deck to the world! In the past year I ended up going to work for Steve and John and they also hired &lt;a href=&quot;http://orderedlist.com/the-team/#brandon-keepers&quot;&gt;Brandon Keepers&lt;/a&gt; and &lt;a href=&quot;http://orderedlist.com/the-team/#matt-graham&quot;&gt;Matt Graham&lt;/a&gt;. In that time our team has been doing a lot of consulting work, making our existing product Harmony better, and we even launched &lt;a href=&quot;http://get.gaug.es/&quot;&gt;Gauges&lt;/a&gt;, a website analytics service.&lt;/p&gt;
&lt;p&gt;The entire time we were working on these other projects we were formulating what we wanted Speaker Deck to be and this summer that plan started to solidify and we got back to work on it. The first big thing that needed to happen was &lt;a href=&quot;http://jonmagic.com/blog/archives/2011/07/27/moving-speakerdeck-to-heroku/&quot;&gt;moving Speaker Deck to Heroku and S3&lt;/a&gt; for hosting.&lt;/p&gt;
&lt;p&gt;This transition only took a few days to initially implement but gave us an easy &amp;amp; affordable way to grow the service into the future. Meanwhile Steve went to town on some UI &amp;amp; UX improvements that would help set us apart from the competition even more.&lt;/p&gt;
&lt;h3 id=&quot;launch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/the-history-of-speaker-deck/#launch&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Launch&lt;/h3&gt;
&lt;p&gt;The last month leading up to launch was pretty intense, hammering out final details and deciding that we wanted to release the product to our users as a free service.&lt;/p&gt;
&lt;p&gt;Then on September 26th we launched it at about 3pm EST. That first day we had over 600 signups and hundreds of presentations were uploaded. It was a rush seeing people use it, getting feedback, fixing bugs, and dreaming about the future.&lt;/p&gt;
&lt;p&gt;In the past week since launch we’ve had many more signups, hundreds more presentations uploaded, and such great feedback that has helped us formulate an even better plan for how to move forward.&lt;/p&gt;
&lt;p&gt;I’ll be posting more about Speaker Deck later this week, talking about some of the triumphs and struggles we’ve had since launch.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Just Write It Down</title>
    <link href="https://jonmagic.com/posts/just-write-it-down/"/>
    <updated>2011-10-03T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/just-write-it-down/</id>
    <content type="html">&lt;p&gt;I struggle with remembering great ideas, not so great ideas, things I want to accomplish, and so much more. Let’s talk about the easiest way to hack our lives so we can be more productive.&lt;/p&gt;
&lt;p&gt;If you find yourself struggling to remember conversations, epiphanies, and just “what should I do next” then you may be struggling with the same thing I am, a lousy memory.&lt;/p&gt;
&lt;p&gt;For years I’ve told people my memory is horrible, but for some reason I never actually took action to rectify the situation! Maybe I was lying to myself and saying “oh, you’ll remember that” or maybe I never made the connection that my memory will never get better without being proactive.&lt;/p&gt;
&lt;p&gt;Today that is changing. Actually, this pattern of figuring things out and then forgetting the solution has been going away slowly yet surely for me for a few months now. How you ask?&lt;/p&gt;
&lt;p&gt;My coworker John (&lt;a href=&quot;http://twitter.com/jnunemaker&quot;&gt;@jnunemaker&lt;/a&gt;) has been encouraging me since I started working with him to write things down. Keep a small notebook with you at all times, record important points from conversations, ideas you have in the middle of doing other things, any little piece of information that might actually be useful in the future.&lt;/p&gt;
&lt;p&gt;Apparently I’m a slow learner as it has taken months to get into the habit of writing things down, but now I’m seeing real improvements in my memory. I don’t even have to read over all of the notes I’ve taken to remember things sometimes. Just the act of writing it down in the first place is helping me create long term storage for that information in my brain.&lt;/p&gt;
&lt;p&gt;I’m working on a lot of little processes in my life to improve my productivity, both at work and at home. Remembering things has been a great first step and I’ve been blessed by the results.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Grim</title>
    <link href="https://jonmagic.com/posts/grim/"/>
    <updated>2011-09-06T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/grim/</id>
    <content type="html">&lt;p&gt;Grim is a simple gem for extracting (reaping) a page from a pdf and converting it to an image as well as extract the text from the page as a string.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jonmagic/grim&quot;&gt;Grim&lt;/a&gt; is my first Ruby gem! Not technically my first OSS contribution, but definitely my first gem. This project came out of &lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; and is used by Speaker Deck whenever you upload a presentation.&lt;/p&gt;
&lt;h3 id=&quot;sample-usage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/grim/#sample-usage&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Sample usage&lt;/h3&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;pdf &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Grim&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reap&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/path/to/pdf&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pdf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count
pdf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;save&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/path/to/image.png&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pdf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text

pdf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;page&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
  puts page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gem is perfect for anyone working with PDF’s that wants to extract single pages as images or the text from a page using Ruby.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Ditch Your Crew</title>
    <link href="https://jonmagic.com/posts/ditch-your-crew/"/>
    <updated>2011-09-03T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/ditch-your-crew/</id>
    <content type="html">&lt;p&gt;Want to be a better programmer and a better person? Ditch your coworkers, go out and meet other peers, ask questions, and most importantly, listen.&lt;/p&gt;
&lt;p&gt;What the heck am I talking about? A little back story is in order.&lt;/p&gt;
&lt;p&gt;Rocky Mountain Ruby conference was this last week and I had the opportunity to attend thanks to a ticket I won on twitter (thank you &lt;a href=&quot;http://bittheory.com/&quot;&gt;@bittheory_&lt;/a&gt;) and the &lt;a href=&quot;http://orderedlist.com/&quot;&gt;company I work for&lt;/a&gt; being generous enough to pay most of my way.&lt;/p&gt;
&lt;p&gt;I attended it without my usual crew and only knew a couple people at the conference, so pretty much as soon as I arrived, making new friends was a necessity. Thankfully I’m not a shy person, so I set about meeting everyone I possibly could.&lt;/p&gt;
&lt;p&gt;Not being surrounded by folks I already know and have been learning from the past few years, not being in my comfort zone, gave me the opportunity to start completely new conversations. This is invaluable if we want to keep pushing ourselves to learn and become better people. I learned more during the three days at this conference than I have the last three months.&lt;/p&gt;
&lt;p&gt;My title and intro were strong words (link bait!) but my point is this. Whether you are out with your coworkers or on your own, be deliberate about getting outside your comfort zone, meeting new people, building new relationships, asking lots of questions, and listening to the answers.&lt;/p&gt;
&lt;p&gt;You will not be disappointed and the world will be a better place for it.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>A waiter once taught me</title>
    <link href="https://jonmagic.com/posts/a-waiter-once-taught-me/"/>
    <updated>2011-08-04T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/a-waiter-once-taught-me/</id>
    <content type="html">&lt;p&gt;While in San Francisco on our long overdue honeymoon I learned a valuable lesson from our waiter at the Farallon restaurant. While the food was amazing, his confidence and pride in their product was the thing that intrigued me.&lt;/p&gt;
&lt;h3 id=&quot;people-expect-great-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-waiter-once-taught-me/#people-expect-great-service&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; People Expect Great Service&lt;/h3&gt;
&lt;p&gt;I expect great service anywhere I go, probably because it’s something I strive for in my vocation. But sometimes people surprise me and most of the time it’s a good surprise.&lt;/p&gt;
&lt;p&gt;One of the hardest customer service jobs I can imagine is serving at a restaurant. I know I couldn’t do it, having to be courteous every second of every diner’s meal, remembering every detail of their order, and finding the perfect balance of when to check up on a table and when to leave it alone.&lt;/p&gt;
&lt;p&gt;Our server was amazing—his timing, menu advice, and interest in our wellbeing set him apart. But the thing I really came away with?&lt;/p&gt;
&lt;h3 id=&quot;confidence-and-pride&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-waiter-once-taught-me/#confidence-and-pride&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Confidence and Pride&lt;/h3&gt;
&lt;p&gt;He had complete confidence, and pride, in the food that they serve. He was glowing with pride when giving recommendations, and absolutely confident that their best was better than anything we could eat anywhere else.&lt;/p&gt;
&lt;p&gt;Not once did he walk up to our table when we were in the middle of a bite, and when he did stop by it wasn’t to ask “is everything ok?” but rather to ask “so what did you think?”&lt;/p&gt;
&lt;h3 id=&quot;asking-the-wrong-question&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-waiter-once-taught-me/#asking-the-wrong-question&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Asking the Wrong Question&lt;/h3&gt;
&lt;p&gt;I never realized until then that asking someone “is everything ok?” while they are consuming your product, is just about the worst thing you could ask. Why?&lt;/p&gt;
&lt;p&gt;First, it prompts a yes or no response, so in that moment they have to decide whether they like or dislike it more. Why give them a chance to form an opinion based on a 50/50 split?&lt;/p&gt;
&lt;p&gt;Second, it conjures this notion that you don’t have supreme confidence in the product you are selling, that there is the possibility you don’t think it’s good enough.&lt;/p&gt;
&lt;h3 id=&quot;asking-the-right-question-at-the-right-time&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-waiter-once-taught-me/#asking-the-right-question-at-the-right-time&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Asking the Right Question at the Right Time&lt;/h3&gt;
&lt;p&gt;Instead, we should be interacting with our customers in a way that shows we are confident in what we are selling and we take pride in the quality of the product.&lt;/p&gt;
&lt;p&gt;When the waiter asked me “so what do you think?” he was requiring me to think about the tastes, the smells, the pairings of ingredients, and I immediately had good thoughts and told him so. In addition, he timed his question so well that it came at a moment where I could stop and think and answer clearly. My mouth wasn’t full and I wasn’t distracted by taking a sip of my wine.&lt;/p&gt;
&lt;p&gt;He listened to my answers and agreed and then would often say, “if you thought that was great, wait and see what I’m bringing you next.” It never failed either—each new course was even better than the previous.&lt;/p&gt;
&lt;h3 id=&quot;making-this-work-in-any-business&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-waiter-once-taught-me/#making-this-work-in-any-business&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Making This Work in Any Business&lt;/h3&gt;
&lt;p&gt;This post is a call to action for us to think before we interact with our customers. How can we convey our confidence and pride in our product and how can we better time our questions to the customer so that they can give us valuable feedback and we can bring them the “next course” with the maximum effect.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Speaker Deck&#39;s Technology Stack</title>
    <link href="https://jonmagic.com/posts/speaker-decks-technology-stack/"/>
    <updated>2011-07-29T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/speaker-decks-technology-stack/</id>
    <content type="html">&lt;p&gt;Ever curious about what the software stack for programs you use looks like? I am, so I thought I’d share what Speaker Deck’s technology stack looks like right now, and then I can look back a year from now and see how much it has changed.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; is a simple application. You upload a PDF of a presentation that has been exported from Keynote, PowerPoint, or something similar, and it turns it into a deck of images that are easily viewed through an HTML5 slide browser.&lt;/p&gt;
&lt;h3 id=&quot;high-level&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/speaker-decks-technology-stack/#high-level&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; High-Level&lt;/h3&gt;
&lt;p&gt;So what makes it tick? Here’s the rundown from a high level:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;html/css/javascript: currently we don’t use Flash anywhere&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.rubyonrails.org/&quot;&gt;Ruby on Rails&lt;/a&gt; web framework&lt;/li&gt;
&lt;li&gt;A bunch of ruby gems which I’ll list below&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mongodb.org/&quot;&gt;MongoDB&lt;/a&gt;, a high-performance document-oriented database&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://redis.io/&quot;&gt;Redis&lt;/a&gt;, an advanced key-value store&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://fog.io/&quot;&gt;FOG&lt;/a&gt;, technically a ruby gem, which gets its own section below, but had to mention it here as it makes storing files in the cloud super easy&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;service-providers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/speaker-decks-technology-stack/#service-providers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Service Providers&lt;/h3&gt;
&lt;p&gt;Platform as a service and software as a service providers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://heroku.com/&quot;&gt;Heroku&lt;/a&gt; is a platform for easily and quickly deploying, hosting, and scaling applications built on Ruby, Node.js, and now Clojure. A simple “git push heroku” lets us deploy to the cloud.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mongohq.com/&quot;&gt;MongoHQ&lt;/a&gt; is where we host our MongoDB database. They manage the servers so we don’t have to.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://redistogo.com/&quot;&gt;Redis To Go&lt;/a&gt; is a hosted Redis database solution. We use Redis for job queues and Redis To Go lets us quickly scale our database to meet our needs at the time.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://aws.amazon.com/s3/&quot;&gt;Amazon Simple Storage Service&lt;/a&gt;, otherwise known as Amazon S3, is a quick and easy way for us to host thousands of slides and PDFs without going broke. They charge by the gigabyte for bandwidth and storage and it’s darn cheap.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ruby-gems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/speaker-decks-technology-stack/#ruby-gems&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Ruby Gems&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rails/rails/tree/3-1-stable&quot;&gt;rails 3.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://flori.github.com/json/&quot;&gt;json&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rails/sass-rails&quot;&gt;sass-rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rails/coffee-rails&quot;&gt;coffee-rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lautis/uglifier&quot;&gt;uglifier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rails/jquery-rails&quot;&gt;jquery-rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nunemaker’s fork of &lt;a href=&quot;https://github.com/jnunemaker/imanip&quot;&gt;imanip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jgarber/redcloth&quot;&gt;RedCloth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jnunemaker/canable&quot;&gt;canable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/technoweenie/faraday&quot;&gt;faraday&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mbleigh/mash&quot;&gt;mash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jnunemaker/mongomapper&quot;&gt;mongo_mapper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jnunemaker/scam&quot;&gt;scam&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mislav/will_paginate&quot;&gt;will_paginate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://fog.io/&quot;&gt;fog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jnicklas/carrierwave&quot;&gt;carrierwave&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/80beans/mm-carrierwave&quot;&gt;mm-carrierwave&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/defunkt/resque&quot;&gt;resque&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jnunemaker/hunt&quot;&gt;hunt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://rubygems.org/gems/newrelic_rpm&quot;&gt;newrelic_rpm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://rubygems.org/gems/exceptional&quot;&gt;exceptional&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are a few more pieces of software we use for testing but this post is already getting kind of long.&lt;/p&gt;
&lt;p&gt;So what are you using in your software stack?&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Compiling Executables on Heroku</title>
    <link href="https://jonmagic.com/posts/compiling-executables-on-heroku/"/>
    <updated>2011-07-28T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/compiling-executables-on-heroku/</id>
    <content type="html">&lt;p&gt;Are you using Heroku and want to run a program not included in the Heroku environment? I’m going to show you how.&lt;/p&gt;
&lt;p&gt;For &lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; we wanted to be able to extract the text from uploaded pdf’s so that we can index them and make them searchable, but the program we’d been using to do this on our dev machines, pdftotext (part of the &lt;a href=&quot;http://foolabs.com/xpdf/&quot;&gt;XPDF&lt;/a&gt; library), wasn’t available on our &lt;a href=&quot;http://heroku.com/&quot;&gt;Heroku&lt;/a&gt; instances.&lt;/p&gt;
&lt;p&gt;On a whim I typed “heroku run bash” and sure enough I was dropped into a bash shell with our Heroku Cedar Stack instance.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;heroku run &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I went into our app’s tmp directory and tried a wget with the xpdf url, but it failed so I tried curl with the -o option to output to file and it worked. Then I unzipped the file and started building it!&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; ftp://ftp.foolabs.com/pub/xpdf/xpdf-3.02.tar.gz &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; xpdf.tar.gz
&lt;span class=&quot;token function&quot;&gt;tar&lt;/span&gt; zxvf xpdf.tar.gz
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; xpdf-3.02
./configure
&lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When it was done building I found the executable we needed, pdftotext, sitting in the xpdf build directory. I scp’d it to my machine, created a bin directory in our app’s folder, and stuck the executable there. Then with a quick git commit and git push to Heroku we were in business!&lt;/p&gt;
&lt;p&gt;If I had an environment locally that was identical to the Heroku instance I could have built it locally, but to ensure it was built to run on the Heroku instance it just made sense to build it there in the first place.&lt;/p&gt;
&lt;p&gt;The bin directory was added to the app’s path automatically so I was able to execute the pdftotext program from inside our Rails app without a hitch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Josh Peek commented on the &lt;a href=&quot;http://news.ycombinator.com/item?id=2816783&quot;&gt;Hacker News post&lt;/a&gt; that he bundled the xpdf source in a &lt;a href=&quot;https://github.com/josh/ruby-xpdf&quot;&gt;gem which compiles itself at runtime&lt;/a&gt;… Probably a better longterm solution as it works if the underlying environment changes enough to break a prebuilt binary.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Moving Speaker Deck to Heroku</title>
    <link href="https://jonmagic.com/posts/moving-speaker-deck-to-heroku/"/>
    <updated>2011-07-27T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/moving-speaker-deck-to-heroku/</id>
    <content type="html">&lt;p&gt;While at RailsConf earlier this year we decided that it would be wise to move Speaker Deck to Heroku and S3, and we finally made it happen.&lt;/p&gt;
&lt;h3 id=&quot;history&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/moving-speaker-deck-to-heroku/#history&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; History&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://speakerdeck.com/&quot;&gt;Speaker Deck&lt;/a&gt; has been my labor of love since June 1st of last year. &lt;a href=&quot;http://orderedlist.com/the-team/#steve-smith&quot;&gt;Steve&lt;/a&gt; and &lt;a href=&quot;http://orderedlist.com/the-team/#john-nunemaker&quot;&gt;John&lt;/a&gt; had the idea and I set about making it happen in my spare time. It launched October 20th 2010 (with a lot of help from Steve and John) and has been purring along quietly since then. We’ve had 38 people request beta signups and as of today 85 presentations have been uploaded.&lt;/p&gt;
&lt;h3 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/moving-speaker-deck-to-heroku/#getting-started&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Getting Started&lt;/h3&gt;
&lt;p&gt;So back to point of this post, we decided that this app, with its hunger for lots of background workers (to process slides) and its desire to scale as adoption grows, mandated that we figure out a scaling strategy that worked for the app, and worked for us and our resources at the moment.&lt;/p&gt;
&lt;p&gt;We had been tossing &lt;a href=&quot;http://heroku.com/&quot;&gt;Heroku&lt;/a&gt; around in the back of our minds for awhile and after talking to a couple of the Heroku guys at &lt;a href=&quot;http://railsconf.com/&quot;&gt;RailsConf&lt;/a&gt; and having them check if their system had some software we needed (imagemagick/ghostscript), we decided to give it a go.&lt;/p&gt;
&lt;p&gt;Just a few days ago I decided to get to work on it after talking to my coworkers about how to make it happen. &lt;a href=&quot;http://orderedlist.com/the-team/#brandon-keepers&quot;&gt;Brandon&lt;/a&gt; and I dug in and implemented storing slides on S3 (instead of MongoDB’s gridfs) in just a few short hours thanks to the &lt;a href=&quot;https://github.com/jnicklas/carrierwave&quot;&gt;Carrierwave&lt;/a&gt; gem.&lt;/p&gt;
&lt;p&gt;It just so happened that this weekend was the &lt;a href=&quot;http://weblog.rubyonrails.org/2011/7/14/rails-3-1-hackfest&quot;&gt;Rails 3.1 hackfest&lt;/a&gt;, so Saturday we upgraded the app to Rails 3.1 and then to use Ruby 1.9.2 so it could run on the &lt;a href=&quot;http://devcenter.heroku.com/articles/cedar&quot;&gt;Heroku Cedar Stack&lt;/a&gt;. Next we started working on deploying to Heroku.&lt;/p&gt;
&lt;h3 id=&quot;deploying&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/moving-speaker-deck-to-heroku/#deploying&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Deploying&lt;/h3&gt;
&lt;p&gt;Deploying ended up being a lot of trial and error. First I ran into an issue with Heroku’s bundler version (a release candidate) not being able to find one of my dependencies, but that was solved with the handy “bundle cache” command. You just do &lt;code&gt;bundle cache&lt;/code&gt; and then check &lt;code&gt;vendor/cache&lt;/code&gt; into your repo and it sends all the gems up (still in the compressed gem form) so bundler can install them from the &lt;code&gt;vendor/cache&lt;/code&gt; dir.&lt;/p&gt;
&lt;p&gt;Finally I couldn’t get my resque workers to run in the right environment, turns out I was missing &lt;code&gt;task &#39;resque:setup&#39; =&amp;gt; :environment&lt;/code&gt; in my Rakefile. Hadn’t needed that on our previous deploy to &lt;a href=&quot;http://linode.com/&quot;&gt;Linode&lt;/a&gt;, so it took awhile for me figure that one out.&lt;/p&gt;
&lt;h3 id=&quot;migrating&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/moving-speaker-deck-to-heroku/#migrating&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Migrating&lt;/h3&gt;
&lt;p&gt;Brandon and I wrote a script to migrate the data on the old Linode server to our local database and at the same time suck the pdf’s out of Mongo on the old server and then put them on S3 rather than keeping them in gridfs. Then a quick mongodump and mongorestore later our production data was synced from my local machine to our new MongoHQ database.&lt;/p&gt;
&lt;p&gt;Now that the pdf’s were on S3 and the mongo database was populated we just had to reprocess the pdf’s into slides. Technically we could have grabbed the already generated slides from the old server, but we really wanted to see how much we could scale our worker processes on Heroku.&lt;/p&gt;
&lt;p&gt;Here’s the fun part! After a few failed starts (I’ll talk about those in a minute) we had 100 heroku workers processing 5000 slides (an intensive imagemagick/ghostscript task) and it ripped thru them all in just a few minutes. It was awesome to watch the resque web console and typing &lt;code&gt;heroku ps:scale worker=100&lt;/code&gt; was a lot of fun!&lt;/p&gt;
&lt;h3 id=&quot;heroku-scaling-gotchya%E2%80%99s&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/moving-speaker-deck-to-heroku/#heroku-scaling-gotchya%E2%80%99s&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Heroku Scaling Gotchya’s&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;DO NOT&lt;/strong&gt; remove workers while you are processing a bunch of stuff unless your jobs are easy to restart. Heroku kills the processes not caring if they were already working on something, leaving jobs in limbo 😕&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DO NOT&lt;/strong&gt; change (upgrade/downgrade) your RedisToGo plan while workers are running, your redis db gets replaced instantly, losing any currently processing jobs.&lt;/p&gt;
&lt;h3 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/moving-speaker-deck-to-heroku/#wrap-up&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Wrap Up&lt;/h3&gt;
&lt;p&gt;Overall this was a fairly painless move and it was so exciting to scale up our background workers and watch 20 slides a second get processed. Now that Speaker Deck is on Heroku and S3 we have one less constraint holding us back from releasing new features and hopefully leaving beta soon.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Best Work Days</title>
    <link href="https://jonmagic.com/posts/the-best-work-days/"/>
    <updated>2011-07-01T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/the-best-work-days/</id>
    <content type="html">&lt;p&gt;Today was an awesome day at work.&lt;/p&gt;
&lt;p&gt;One of my favorite kind of work days is when we’re all working on different things, we’re all in the zone, and we’re all in the same room. Today was one of those days with Steve, John, and I all hacking on new features for &lt;a href=&quot;http://orderedlist.com/products/&quot;&gt;our products&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Every hour or two one of us would leave our keyboard and gather the others to show what we’d got done and take input from the other two. Then the others would take their turns in the spotlight.&lt;/p&gt;
&lt;p&gt;For me at least this routine throughout the day kept me pumped up and excited about my progress and pushed me to make even more headway.&lt;/p&gt;
&lt;p&gt;I’m pretty psyched about what each of us are working on and I’m really excited to show you soon!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Starting to Unplug</title>
    <link href="https://jonmagic.com/posts/starting-to-unplug/"/>
    <updated>2011-06-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/starting-to-unplug/</id>
    <content type="html">&lt;p&gt;Changing the way you live your life sounds weird, and drastic, but I have to admit that I’m really starting to enjoy it.&lt;/p&gt;
&lt;p&gt;I have been constantly connected to everyone I know, via my cell phone and the internet, for over a decade and a half now, except for a few rare occasions (like my wedding) where I left the cell phone behind.&lt;/p&gt;
&lt;p&gt;It has always frustrated me that my wife often won’t reply to emails for weeks, never cared to hang out on twitter, was never interested in reading my blog, and basically has never made modern communication (even her cell phone, she rarely answers it) an important part of her daily routine. But she seems perfectly happy and a lot of the time less stressed than myself, so I decided to re-evaluate how I use these tools to see if I’m doing it wrong.&lt;/p&gt;
&lt;p&gt;Since I left my job at &lt;a href=&quot;https://web.archive.org/web/2012/https://web.archive.org/web/2012/http://sabretechllc.com&quot;&gt;SabreTech&lt;/a&gt; the first big change I made was leaving my phone on silent all day, everyday, unless I’m expecting a call that I really want to get. The iPhone still vibrates, so if it’s in my pocket or next to my hands on my desk I’ll notice it ringing, and most of the time I’ll pick it up. But not worrying about getting every call is a better way to live, trust me.&lt;/p&gt;
&lt;p&gt;Next up was not hovering over &lt;a href=&quot;http://twitter.com/jonmagic&quot;&gt;twitter&lt;/a&gt; every second of the day. I still open it three or four times at work and a half a dozen times in the evening, but it’s not open all the time anymore, with its little icon constantly distracting me that there are new tweets waiting to be read. Another source of anxiety lifted.&lt;/p&gt;
&lt;p&gt;A new source of anxiety introduced itself last year when I started playing Words with Friends. I quickly learned that I would go insane if I didn’t turn off the notifications it sends you every time someone you’re playing against takes their turn. Later I learned how to turn off the badge notification telling me how many games were waiting on me.&lt;/p&gt;
&lt;p&gt;But the biggest change I’ve made to date was two weeks ago when I turned off push email on my iPhone. In fact, unless I open my mail app it &lt;strong&gt;NEVER&lt;/strong&gt; goes out and checks for new mail. Now I check my mail in the morning when I get up, keep my mail client open during the day for work, and then don’t look at it again until the next morning. This has been a huge change, for two reasons.&lt;/p&gt;
&lt;p&gt;First, I’m not constantly distracted while spending time with my friends and family. They get more of my attention, which makes them happier.&lt;/p&gt;
&lt;p&gt;Second, I’m not constantly being reminded of work and what I have to do the next day. I can actually spend time enjoying life outside of work, I can stop obsessing on silly things, and I can just enjoy all of God’s blessings.&lt;/p&gt;
&lt;p&gt;Try it, but let me warn you, you’ll probably like it 😃&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Obsession and Understanding</title>
    <link href="https://jonmagic.com/posts/obsession-and-understanding/"/>
    <updated>2011-06-29T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/obsession-and-understanding/</id>
    <content type="html">&lt;p&gt;I’ve been emotionally up and down a lot the past few months and a lot of it has had to do with work. Don’t get me wrong, I love my job, and therein lies the problem.&lt;/p&gt;
&lt;p&gt;I’ve always been very passionate about my work, but as I get older and learn more about life, I’m realizing I need to put things into better perspective.&lt;/p&gt;
&lt;p&gt;Obsessing about one area of your life is unhealthy. Religion, politics, work, hobbies, or family; obsessing over any of these can lead to anxiety, stress, and dissatisfaction with life.&lt;/p&gt;
&lt;p&gt;God has been teaching me lately that I need to put my hope in Him, that I need to understand my joy will never come directly from any of those areas of life I mentioned above, but that it can come from recognizing His work in my life in all of those arenas.&lt;/p&gt;
&lt;p&gt;Right now I need to stop obsessing on what I want out of my job, and start understanding how I’m learning and growing in my job.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Thank you</title>
    <link href="https://jonmagic.com/posts/thank-you/"/>
    <updated>2011-06-08T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/thank-you/</id>
    <content type="html">&lt;p&gt;Recognizing someone’s hard work and thanking them for it is always worth it.&lt;/p&gt;
&lt;p&gt;I’m in Dallas right now on business and one of the nice things about the place I’m staying at is they always give you a tray of three chocolates on your bed when you first arrive.&lt;/p&gt;
&lt;p&gt;Well, I ate my three chocolates within 48 hours of arriving and this morning all I could think about was having another one. So selfishly I began to compose a message on the notepad next to my bed asking for more.&lt;/p&gt;
&lt;p&gt;While writing the little note to the person who cleans the room I began to think how awesome it was that they actually took the time to do it, making my bed, replacing the towels, emptying the trash, and who knows what else.&lt;/p&gt;
&lt;p&gt;So I ended up writing a note to them thanking them for their hard work and politely asking if it was possible for me to get another chocolate. I even made a little papier-mache flower out of one of the used chocolate wrappers.&lt;/p&gt;
&lt;p&gt;When I got back to my room later in the day the tray was on the bed with five, YES, FIVE, chocolates!&lt;/p&gt;
&lt;p&gt;Moral of the story? Think about what others do for you, even if it is their job, and thank them for it. They will appreciate it and you’ll get chocolate (ok, so maybe not all the time).&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Smoker - Back Story and First Day</title>
    <link href="https://jonmagic.com/posts/the-smoker---back-story-and-first-day/"/>
    <updated>2011-05-12T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/the-smoker---back-story-and-first-day/</id>
    <content type="html">&lt;p&gt;I’ve been planning on building a 55 gallon smoker for almost a year and a half now, but the time and resources just haven’t been there. Today marked the first day of real progress!&lt;/p&gt;
&lt;p&gt;It all started when this &lt;a href=&quot;http://jmillerid.com/wordpress/2009/12/55-gallon-drum-smoker/&quot;&gt;blog post&lt;/a&gt; appeared a year and a half ago. I saw it and I immediately fell in love. I’d only been smoking for a few months at that point, with a $35 Brinkman, but I’d already developed a passion for good BBQ.&lt;/p&gt;
&lt;p&gt;In the spring of 2010 I jumped on Craigslist and found a couple of barrels only 2 miles from my house, and immediately bought them. But then, as often happens to me, I set the dream of building it aside because of fear of starting and my many excuses like lack of tools, lack of time, etc.&lt;/p&gt;
&lt;p&gt;But the dream persisted, and when I found out my parents would be returning from Argentina for a few months this summer I decided to enlist my dad’s help and get this thing rockin!&lt;/p&gt;
&lt;p&gt;A week ago we set today as the day to begin, which left me just a few days to prepare. Preparation meant getting a jigsaw, a welder, and this &lt;a href=&quot;http://jmillerid.com/wordpress/wp-content/uploads/2009/12/intersecting_curve2.jpg&quot;&gt;curve pattern&lt;/a&gt; printed to scale. I decided the building would need to be broken into phases, for financial and time reasons, so this first day I limited to just needing the jigsaw and curve pattern.&lt;/p&gt;
&lt;p&gt;Buying a jigsaw, easy. Printing a 70” curve, not as easy 😕&lt;/p&gt;
&lt;p&gt;The story of acquiring the curve requires some back story. Again, I’ve been planning on building this thing for over a year, so I actually started searching out a plotter to print it a year ago. At the time I worked at &lt;a href=&quot;https://web.archive.org/web/2012/https://web.archive.org/web/2012/http://sabretechllc.com&quot;&gt;SabreTech&lt;/a&gt; and we had quite a few industrial clients with printers, but I never managed to find the right place to get it done.&lt;/p&gt;
&lt;p&gt;One day seven or eight months ago while visiting my college friend Bob at his workplace &lt;a href=&quot;http://daavlin.com/&quot;&gt;Daavlin&lt;/a&gt; (also one of our best clients) I noticed they had a plotter. Bob proceeded to explain that they’d just acquired it, but hadn’t figured out way to hook it up yet (older interface that none of their computers had). I offered to help (I think) in exchange for printing the curve, but he said he’d get it running and told me he’d print the curve anyways.&lt;/p&gt;
&lt;p&gt;Fast forward to yesterday morning (seven+ months later). I left for work thinking that I’d need to find a way to print that curve. I got halfway to work and realized I’d forgotten my lunch, so I turned around and went back home. As I pulled in the driveway I noticed a package on the front step. I grabbed it, ran inside, cut open the package, and lo and behold there was my curve printed to scale! Somehow Bob managed to time printing and sending it to me so perfectly that it arrived the day I was going to print it myself. Awesome.&lt;/p&gt;
&lt;p&gt;So today I went and grabbed a jigsaw, some blades for cutting metal, and dad and I got to work this evening. We focused just on the cutting phase, and knocked it out in short order! &lt;a href=&quot;http://www.flickr.com/photos/jonmagic/sets/72157626583429183/show/&quot;&gt;Here are some pics&lt;/a&gt; for your enjoyment 😃 Sorry, forgot to wear a shirt in a few 😕&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Priorities</title>
    <link href="https://jonmagic.com/posts/priorities/"/>
    <updated>2011-03-05T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/priorities/</id>
    <content type="html">&lt;p&gt;Balancing your home and work life can be terribly difficult, especially when you love your job.&lt;/p&gt;
&lt;h3 id=&quot;shut-it-off&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/priorities/#shut-it-off&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Shut It Off&lt;/h3&gt;
&lt;p&gt;Last night my wife and I went on a date, first out to dinner and then to grab a movie to watch at home. Once back home she was getting ready to watch the movie while I popped the DVD in and queued it up.&lt;/p&gt;
&lt;p&gt;I popped open my laptop and noticed our work chat had been blowing up and instantly got sucked in. My coworkers were hacking on &lt;a href=&quot;http://gaug.es/&quot;&gt;Gaug.es&lt;/a&gt; and doing some awesome stuff with async and EventMachine and I immediately wanted to be a part of it.&lt;/p&gt;
&lt;p&gt;Instead I closed my laptop just in time to see my wife coming into the living room ready to watch the movie. This wasn’t an easy decision, but it was the right decision, one I haven’t made hundreds of times in the past, to the detriment of our relationship.&lt;/p&gt;
&lt;p&gt;Spending time with your loved ones (in my case my wife and dogs) must take priority over your work life. What kind of message do you send to them if you always leave that laptop open? Not that you are dedicated, or that you are providing for them, you are sending the message that you care more about work than you care about them. They don’t get over this easily, trust me.&lt;/p&gt;
&lt;p&gt;I’m not saying you can’t work at home or in the evenings, I’m saying that it’s important to set aside and dedicate &lt;strong&gt;the majority&lt;/strong&gt; of your home life to spending time with and sharing your life with those you love.&lt;/p&gt;
&lt;h3 id=&quot;dream-at-home&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/priorities/#dream-at-home&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Dream At Home&lt;/h3&gt;
&lt;p&gt;One of the reasons it has been so easy for me to make the wrong decision in the past, to work late every night, is that I love my work, I’m excited about it, and often that excitement feels greater than anything I’m excited about at home.&lt;/p&gt;
&lt;p&gt;It has been important for my wife and I to find things that we’re both excited about, which in our case is food and travel, and spend time talking about or doing those things every day. We spend anywhere from one to three hours in the kitchen every night, cooking, sharing stories from our day, &lt;a href=&quot;http://orderedlist.com/blog/articles/share-the-dream/&quot;&gt;sharing our dreams&lt;/a&gt; and just being best friends. No computers (except to play some music), no hacking, just spending quality time together enjoying each other’s company.&lt;/p&gt;
&lt;h3 id=&quot;exceptions-to-the-rule&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/priorities/#exceptions-to-the-rule&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Exceptions to the Rule&lt;/h3&gt;
&lt;p&gt;Having said all that, I still choose to work late two or three evenings every week. I feel like (and my wife agrees) that it is hard to get ahead in life, hard to take things to the next level, if you don’t kick it up a notch every once in awhile.&lt;/p&gt;
&lt;p&gt;My wife and I don’t plan on living in Elkhart, Indiana the rest of our lives, we dream of moving to Italy, so we feel like burning the midnight oil a couple nights a week to make that dream happen sooner is totally worth it.&lt;/p&gt;
&lt;p&gt;The last thing I would caution on working at home is that you prepare for it, warn those who may depend on you so they can plan accordingly. I also try and pitch in a little extra effort that day, making sure chores are done, whatever I can do so she doesn’t feel like she’s on her own.&lt;/p&gt;
&lt;p&gt;P.S. I had no idea it was the &lt;a href=&quot;http://www.huffingtonpost.com/2011/03/04/national-day-of-unplugging_n_831176.html&quot;&gt;National Day of Unplugging&lt;/a&gt; when I wrote this.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Share the Dream</title>
    <link href="https://jonmagic.com/posts/share-the-dream/"/>
    <updated>2011-03-03T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/share-the-dream/</id>
    <content type="html">&lt;p&gt;Sharing in the vision and energy of your team is a key factor to success and happiness at work.&lt;/p&gt;
&lt;h3 id=&quot;putting-your-dreams-on-hold&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/share-the-dream/#putting-your-dreams-on-hold&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Putting Your Dreams On Hold&lt;/h3&gt;
&lt;p&gt;When I started at OrderedList there was &lt;a href=&quot;http://speakerdeck.com/&quot;&gt;one product&lt;/a&gt; I was really passionate about because I had done most of the work on it. I quickly realized though that I needed to put that passion on hold, or better said, redirect it towards Harmony, so that I could help push the vision of my team forward. I needed to share their dreams and hopefully incorporate mine at some point.&lt;/p&gt;
&lt;p&gt;As soon as I dug into Harmony, fixing weak spots in the test suite, spearheading the move to Rails 3, working on a new feature (&lt;strong&gt;that I’m dying to tell you about&lt;/strong&gt;), my heart began to change, my passion became their passion, and I was happy again and part of the team.&lt;/p&gt;
&lt;h3 id=&quot;sharing-the-energy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/share-the-dream/#sharing-the-energy&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Sharing The Energy&lt;/h3&gt;
&lt;p&gt;Almost as soon as I really started getting passionate about Harmony John came home from sick leave and had this crazy idea to build a &lt;a href=&quot;http://gaug.es/&quot;&gt;web analytics service&lt;/a&gt;, which we now call &lt;a href=&quot;http://gaug.es/&quot;&gt;Gauges&lt;/a&gt;. At first all I could think was, &lt;strong&gt;boring&lt;/strong&gt;, but hanging around Steve, John, and Brandon I started to catch the buzz, the energy, and the excitement!&lt;/p&gt;
&lt;p&gt;This is when I began to realize that I didn’t necessarily have to put my dreams on hold, I just needed to share in my team’s excitement and get them excited about what I’m excited about by letting them see my own energy.&lt;/p&gt;
&lt;p&gt;Every team is different, but letting your coworkers see your excitement and passion about a product/project and sharing in their dreams at the same time is one easy way to stay happy at work and be excited to go to the office every day.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>New Guy Blues</title>
    <link href="https://jonmagic.com/posts/new-guy-blues/"/>
    <updated>2011-03-02T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/new-guy-blues/</id>
    <content type="html">&lt;p&gt;Being the new guy in your workplace can be intimidating. It can cause anxiety, frustration, and hamper your productivity. Sometimes it’s your coworkers not making it easy for you, sometimes it’s just you, your mindset, willingness to stretch your limits.&lt;/p&gt;
&lt;p&gt;I’m one of the new guys at OrderedList and I’d like to share three things that helped me jumpstart my productivity at OrderedList and catapult me to being a key part of the team.&lt;/p&gt;
&lt;h3 id=&quot;servants-heart&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-guy-blues/#servants-heart&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Servants Heart&lt;/h3&gt;
&lt;p&gt;This is something we should all apply, regardless of whether we’re the new guy, but it’s especially helpful when trying to fit into a new environment. Having a servant’s heart means you are constantly looking for the best way to serve those around you.&lt;/p&gt;
&lt;p&gt;You notice someone has a stuffy nose, grab them some kleenex. A coworker is frustrated with what he’s working on, ask him if he’d like to use you as a sounding board.&lt;/p&gt;
&lt;p&gt;Being aware of others’ needs and acting on it makes you instantly useful to the team and endears you to them.&lt;/p&gt;
&lt;h3 id=&quot;find-a-mentor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-guy-blues/#find-a-mentor&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Find A Mentor&lt;/h3&gt;
&lt;p&gt;Starting a new job means learning how to do new things. Some people can just jump in without help and do an amazing job; I’m not one of those people. I found at this job that watching, recognizing, and imitating patterns of work was the quickest way for me to get directly involved in what we do.&lt;/p&gt;
&lt;p&gt;Thankfully I have the opportunity almost every day to pair program with our other new guy, &lt;a href=&quot;http://orderedlist.com/the-team/#brandon-keepers&quot;&gt;Brandon&lt;/a&gt;, who has years more experience than I do. I do the best I can as a pair partner, catching typos, helping with decisions, and more, but most importantly I’m watching every line of code he writes, understanding it, and asking questions when I don’t, so that later I can imitate and create beautiful code.&lt;/p&gt;
&lt;p&gt;I could just dive in on projects and do things the way I know how to do them, but finding someone smarter than you to imitate pushes you to continue expanding what you know how to do.&lt;/p&gt;
&lt;h3 id=&quot;do-what-you-know&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/new-guy-blues/#do-what-you-know&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Do What You Know&lt;/h3&gt;
&lt;p&gt;The past month and a few days we’ve been working on a new product, &lt;a href=&quot;http://gaug.es/&quot;&gt;Gauges&lt;/a&gt;, in our spare time. A lot of the tech on this project I had never used before, so initially I found it hard to jump in and help. I paired and helped when I could, but I really wanted to contribute on my own. Then the opportunity arose to work on the admin section, something I knew how to do.&lt;/p&gt;
&lt;p&gt;I dove right in, here was something I could contribute with little to no help from my team, and it was something that they could appreciate day to day. Sometimes you need to step back, do what you know, and get that instant rush of being a valuable member on the team, a contributor, and not so much the new guy anymore.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>A WebDev&#39;s notes on native Android/iPhone app development</title>
    <link href="https://jonmagic.com/posts/a-webdevs-notes-on-native-androidiphone-app-development/"/>
    <updated>2010-11-26T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/a-webdevs-notes-on-native-androidiphone-app-development/</id>
    <content type="html">&lt;p&gt;I was contracted to build a fairly simple phototherapy treatment time calculator app for one of our clients recently, and in the process learned A LOT about developing for the iPhone and Android using html/css/javascript.&lt;/p&gt;
&lt;p&gt;The requirements for the job were that the final app feel native and that it be able to be purchased on the respective market place (Appstore or Android Market).&lt;/p&gt;
&lt;p&gt;I’d already written the &lt;a href=&quot;http://itunes.apple.com/us/app/daavlin-phototherapy-dose/id386168638?mt=8&quot;&gt;app once for the iPhone&lt;/a&gt;, using the &lt;a href=&quot;http://www.jqtouch.com/&quot;&gt;jqTouch&lt;/a&gt; library and then wrapping the whole thing with &lt;a href=&quot;http://www.phonegap.com/&quot;&gt;PhoneGap&lt;/a&gt;, but this time around the client wanted to add some features that made me look further than jqTouch.&lt;/p&gt;
&lt;p&gt;Initially I fantasized about a write once deploy twice approach using something like &lt;a href=&quot;http://www.appcelerator.com/products/titanium-mobile-application-development/&quot;&gt;Appcelerator Titanium&lt;/a&gt;. The more I read however the more I realized no matter how I went about this project I was going to end up with more than one codebase, one for the iPhone and at least one for the Android. I decided to go ahead with Appcelerator however and developed for the iPhone first. One of the biggest things I was looking for was a native bottom tab bar for navigating between the different phototherapy calculators (UVB, UVA, UVA1, and Blue), and Appcelerator let me quickly build a native, beautiful, functional app that exactly fit the clients needs.&lt;/p&gt;
&lt;p&gt;After a bit of troubleshooting I had it deploying to my actual iPhone, but no matter how hard I tried I could never manage to get it to deploy to the Android emulator.&lt;/p&gt;
&lt;p&gt;Next I started working on a &lt;a href=&quot;http://www.sencha.com/products/touch/&quot;&gt;Sencha Touch&lt;/a&gt; version of the app, which I planned to wrap with PhoneGap, but after about an hour of digging around in Sencha I decided it didn’t fit my programming aesthetic. I also talked to someone who wrote an app in Sencha and they said it had a ways to go with speed, animations were still jerky on older hardware.&lt;/p&gt;
&lt;p&gt;Finally I decided to give &lt;a href=&quot;http://jquerymobile.com/&quot;&gt;JqueryMobile&lt;/a&gt; a try (thanx Xian!) and it was a great fit for a webdev like me. Using the latest PhoneGap and JqueryMobile I had the app rewritten and running on the Android Emulator in just under 2 hours, and then another 2 hours tweaking the interface and interactions. If you know html/css/javascript, you can write a fairly native feeling app in no time with JqueryMobile.&lt;/p&gt;
&lt;p&gt;Having used jqTouch, Appcelerator, JqueryMobile, PhoneGap, and having looked at Sencha, I have to say Appcelerator was by far the best experience. I enjoyed programming the interface rather than laying out the html and then styling it with CSS. I enjoyed how quickly and easy it was to deploy to the iPhone (I wish it could do the same for Android!). Most of all I loved how it built a native interface, which beats an html5 interface almost every time in my opinion.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>What laptop to get?</title>
    <link href="https://jonmagic.com/posts/what-laptop-to-get/"/>
    <updated>2010-11-20T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/what-laptop-to-get/</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://jonmagic.com/post/1611565836/hey-mom-i-got-a-job&quot;&gt;As you know&lt;/a&gt;
I’m taking a new job. New job means new laptop, and I’m having a terrible time deciding what Mac to get. Just browsing Apple’s website I fell in love with the new &lt;a href=&quot;https://www.apple.com/macbookair/&quot;&gt;13” Macbook Air&lt;/a&gt;, but the feedback on Twitter has been 50/50 for/against. Some think it works just fine as a development machine, especially with the rockin’ SSD and 4GB of RAM, but others worry that going from MBP to the Air will leave you wanting.&lt;/p&gt;
&lt;p&gt;I’ve been using a 15” 2.53 GHz Core 2 Duo Macbook Pro with 4GB of RAM for a few months now, and even it is not fast enough for me (looks like it’s the HDD that’s the bottleneck most of the time though).&lt;/p&gt;
&lt;p&gt;I figured I needed some hands on, so I stopped by our &lt;a href=&quot;http://gowalla.com/spots/6424797&quot;&gt;new Apple store in Mishawaka&lt;/a&gt; today and played with several different models.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;11” Macbook Air:&lt;/strong&gt; this thing is tiny. I liked it except for the giant surround around the screen, it makes the screen look way too small. Give me a 1/2 to 3/4 bezel, not an inch and a quarter!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;13” Macbook Air:&lt;/strong&gt; wow is she pretty, but it would definitely take some getting used to. It has the same number of pixels as my 15” but crammed into a 13” screen. I do love the weight to size ratio though. I couldn’t really run any speed tests, but the thing was dang fast from what I could tell.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;15” Macbook Pro:&lt;/strong&gt; I tried out one of the i5’s with 8GB of RAM and an SSD and it was screaming. The only downside is the thickness/weight.&lt;/p&gt;
&lt;p&gt;My conclusion at this moment in time is that Apple needs to make me a 15” Macbook Air! I don’t need an optical drive, I want tons of pixels, but I also want that bigger 15” screen. Imagine a 15” with an i5 processor, still super thin, and a 10 hour battery, all weighing under 4 pounds. I say hot hot hot…&lt;/p&gt;
&lt;p&gt;I know it’s a pipe dream, but hey, boys gotta dream sometimes right?&lt;/p&gt;
&lt;p&gt;I’d love to hear from anyone using the new Macbook Air, what has your experience been?&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Hey mom, I got a job!</title>
    <link href="https://jonmagic.com/posts/hey-mom-i-got-a-job/"/>
    <updated>2010-11-18T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/hey-mom-i-got-a-job/</id>
    <content type="html">&lt;p&gt;How a butler was born.&lt;/p&gt;
&lt;p&gt;Well folks, 2010 has been quite a year. Three of my close friends got married, my lil’sis is getting married next month, my best friend is having a baby, and I have decided to leave SabreTech and take a job at OrderedList.&lt;/p&gt;
&lt;p&gt;Woh! Wait a second Jon, aren’t you part owner in SabreTech? Indeed I am, but with the news of my departure my business partners have decided to buy me out.&lt;/p&gt;
&lt;p&gt;So how did I get to where I’m at now?&lt;/p&gt;
&lt;p&gt;First I’d like to take a quick look back. I bought SabreTech in 2005 with Brad Cochran and together we turned it into a profitable and growing business. In 2007 Sam Sallows joined the team and we made him a partner in a little over a year. SabreTech has been growing since we bought it, but the addition of Sam really made things go crazy. SabreTech has grown 400% in 5 years and the rate of growth is increasing.&lt;/p&gt;
&lt;p&gt;After my wife and I moved to Indiana in 2007 with the hopes of expanding SabreTech, it quickly became apparent that the economy in Elkhart couldn’t support a second store. To make up for my down time in Indiana I started to really apply myself at software development, learning everything I could. That love of programming took me to a &lt;a href=&quot;https://groups.google.com/g/southbendrb&quot;&gt;little group&lt;/a&gt; that met monthly at Notre Dame to talk about programming (specifically about using Ruby and Rails). At that meeting I met Steve Smith and John Nunemaker.&lt;/p&gt;
&lt;p&gt;Steve had left Notre Dame to start OrderedList and shortly after I met them John left Notre Dame to join Steve. Over the past couple of years we started to hang out more during work hours (meeting in coffee shops and eventually at their office) and after hours (Notre Dame tailgates, the Super Bowl).&lt;/p&gt;
&lt;p&gt;Apparently John and Steve saw something in me that they liked, because they offered me a job, and yesterday my wife and I decided to take it.&lt;/p&gt;
&lt;p&gt;That brings us to today, two weeks and one day before my last day of work at SabreTech. I start at OrderedList on December 6th! I’ll be handling customer support for their product Harmony, as well as programming on various projects from SpeakerDeck to client work.&lt;/p&gt;
&lt;p&gt;This will be the first time in 10 years that I haven’t been a business owner and have an actual boss (already practicing my “yes boss”). I’m sure it will be an adjustment, but I honestly look forward to having less stress, better hours, and a 20 minute commute (as opposed to 90).&lt;/p&gt;
&lt;p&gt;I’m crazy excited to be working with Steve and John, they are two of the smartest people I know, and both love to teach and push their peers to the limit. I’m going to be in an environment where constantly learning new things is a necessity, not just an aspiration.&lt;/p&gt;
&lt;p&gt;So yeah, mom, I went and got a job 😉&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; &lt;a href=&quot;https://web.archive.org/web/2011/http://orderedlist.com/our-writing/blog/articles/welcome-jon-hoyt/&quot;&gt;Read the announcement over on the OrderedList blog&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Vacation Reviews</title>
    <link href="https://jonmagic.com/posts/vacation-reviews/"/>
    <updated>2010-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/vacation-reviews/</id>
    <content type="html">&lt;p&gt;We’re just now back from a great trip to Boston MA, Concord NH, and Milton VT. From trying oysters to a tasting at a winery, our foodie passions drove us to try new things. We made sure to post our reviews on Yelp when we returned home!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/neptune-oyster-boston#hrid:t315xMhq1YuU-h52ZLPw8g&quot;&gt;Neptune Oyster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/mikes-city-diner-boston#hrid:sEyFHgCu8Nl3gDj1rksOcA&quot;&gt;Mike’s City Diner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/pizzeria-regina-boston-4#hrid:z08r9gNXe3xL3tEkQkJz4g&quot;&gt;Regina’s Pizza&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/boston-chowda-co-boston#hrid:Cb7QHZYATYTS9lgP80bYxA&quot;&gt;Boston Chowda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/fire-and-ice-boston#hrid:wq_xlJSRFjiriA_XNx4j3g&quot;&gt;Fire &amp;amp; Ice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/the-barking-crab-boston#hrid:_T1l71OuohNd2JcqkKY0bA&quot;&gt;Barking Crab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/sullivans-pub-charlestown#hrid:bCgMZ8_mGYl_urDOlfB7Ag&quot;&gt;Sullivan’s&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/boyden-valley-winery-jeffersonville#hrid:9yIO5qalMWITHxbxdpPnfQ&quot;&gt;Boyden Valley Winery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/apollo-diner-milton#hrid:NOqBsU3Wp2FZRSfR9vp-Dg&quot;&gt;Apollo Diner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/ri-ra-the-irish-pub-burlington#hrid:Jcttbb_xQDd2b9WTLO0T_Q&quot;&gt;Ri Ra Irish Pub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.yelp.com/biz/schwabls-restaurant-west-seneca#hrid:JEcTe1GQ_giQhuCA-uYObQ&quot;&gt;Schwabl’s Restaurant&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to eating our hearts out, I’d also like to mention the &lt;a href=&quot;http://jonmagic.com/post/1219753840/46-monument-avenue&quot;&gt;amazing place we stayed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We definitely love traveling, and this particular trip fulfilled many a dream!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>46 Monument Avenue</title>
    <link href="https://jonmagic.com/posts/46-monument-avenue/"/>
    <updated>2010-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/46-monument-avenue/</id>
    <content type="html">&lt;p&gt;This summer my wife and I planned a trip to Boston for our best friend’s wedding. While getting ready to book a room I came across &lt;a href=&quot;http://techcrunch.com/2010/07/25/fawlty-logic/&quot;&gt;an article&lt;/a&gt; about &lt;a href=&quot;http://airbnb.com/&quot;&gt;airbnb.com&lt;/a&gt;, so I decided to give it a try. The first 3 attempts to get a room failed, but each time Airbnb sent me a better coupon so I kept trying. The fourth attempt got me &lt;a href=&quot;http://www.airbnb.com/rooms/45987&quot;&gt;46 Monument Avenue&lt;/a&gt;, and it was the best purchase I’ve made in a year.&lt;/p&gt;
&lt;p&gt;For a very reasonable price ($100 per night) we got a cute studio apartment with a private patio, in Charlestown, just a short distance from the North Side.&lt;/p&gt;
&lt;p&gt;The host, Atef Aziz, emailed us before arrival to find out more about us. He was helpful enough to get us into the room at 10am on our check-in day, rather than having to wait until 3 or 4pm (like most hotels). He was eager to help in any way, from walking or driving directions, to restaurant recommendations.&lt;/p&gt;
&lt;p&gt;The apartment is adorable, a studio apartment with a nice large bathroom and stand-up shower. It had a functional kitchen (larger than our kitchen at home), washer/dryer, TV with basic channels, Wi-Fi internet, and an amazing little patio. The patio has a fountain with goldfish, a table with umbrella and chairs, a charcoal grill (the only way to grill), and lots of flowers and fauna. The apartment was only a 10-minute walk to the North Side of Boston and an 8-minute walk to the T (orange line).&lt;/p&gt;
&lt;p&gt;The shower was initially not as hot as I like my showers, but a quick email to Atef got that fixed. The apartment was small, but open, and the kitchen entirely usable. The first night it was a bit warm, so I mentioned it to Atef and he got us a fan, which fixed the problem. The patio was perfect for relaxing in the morning, hanging out during the day, and winding down at night.&lt;/p&gt;
&lt;p&gt;I can’t recommend &lt;a href=&quot;http://www.airbnb.com/rooms/45987&quot;&gt;46 Monument Avenue&lt;/a&gt; and Atef Aziz enough. From his hospitality to the beautifully furnished accommodations, this stay in Boston was a delight.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/2012/https://web.archive.org/web/2012/http://www.46monumentavenue.com/&quot;&gt;See more about his rental here.&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Death of Free</title>
    <link href="https://jonmagic.com/posts/the-death-of-free/"/>
    <updated>2010-09-09T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/the-death-of-free/</id>
    <content type="html">&lt;p&gt;I’m predicting the death of free in the next one or two years. You heard it here first.&lt;/p&gt;
&lt;p&gt;What the heck am I talking about? It used to be in our house that we only used services on the internet that were free, flickr, delicious, youtube, clearcheckbook, etc. In the past two years we have shifted to using Flickr Pro, Pinboard, Vimeo Pro, ClearCheckBook Pro, Rdio, and Netflix streaming, just to name a few.&lt;/p&gt;
&lt;p&gt;Not only have we upgraded to the pro version of almost every internet service we use, but we also usually don’t start using a new service unless it has a paid version. Why? There are two primary reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Companies charging money for their service are more likely to be around in 5 years.&lt;/li&gt;
&lt;li&gt;I’m more likely to use a service if I’m paying for it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second reason is more interesting. It helps me weed out things in my life that are wasting my time. If I’m not willing to pay for something to use it, it most likely isn’t worthy of me spending any time to use it.&lt;/p&gt;
&lt;p&gt;I think my generation (and my gen’s kids) are finally starting to take to heart the old saying “you get what you pay for”. Free stuff is for the most part crap, has strings attached, and ends up being a time sink.&lt;/p&gt;
&lt;p&gt;The Freemium model still works, but I think its on the way out. The model that makes more sense to me is either just a great demo &amp;amp; paid service, or a free trial that pushes to paid.&lt;/p&gt;
&lt;p&gt;Of course the irony of this post is I’m not paying for &lt;a href=&quot;http://tumblr.com/&quot;&gt;Tumblr&lt;/a&gt;, and I can’t seem to find anywhere where I can give them money. However, I am choosing &lt;a href=&quot;http://tumblr.com/&quot;&gt;Tumblr&lt;/a&gt; as my micro-blogging platform over &lt;a href=&quot;http://posterous.com/&quot;&gt;Posterous&lt;/a&gt; because I think they are more likely to have a paid version in the future.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Make Asterisk use Gmail for emailing faxes</title>
    <link href="https://jonmagic.com/posts/make-asterisk-use-gmail-for-emailing-faxes/"/>
    <updated>2009-09-10T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/make-asterisk-use-gmail-for-emailing-faxes/</id>
    <content type="html">&lt;p&gt;While &lt;a href=&quot;http://www.asterisk.org/&quot;&gt;Asterisk&lt;/a&gt; provides a simple way to replace sendmail when sending voicemails, the incoming fax portion of Asterisk is not so easily reconfigured. By studying how it handled an incoming fax from the Asterisk CLI I was able to find this perl script: &lt;a href=&quot;https://gist.github.com/184641/ddea153508f3373cf2f99ac8ba79fe99ce6fc2fd&quot;&gt; /var/lib/asterisk/bin/fax-process.pl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This script uses Net::SMTP to send its faxes as attachments via email. We (and by we I mean &lt;a href=&quot;http://www.behindlogic.com/&quot;&gt;Daniel&lt;/a&gt;) rewired the perl script to use Net::SMTP::SSL instead and made it work with gmail!&lt;/p&gt;
&lt;p&gt;There were a few libraries I had to install via cpan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;force install F/FL/FLORA/Net_SSLeay.pm-1.30.tar.gz&lt;/li&gt;
&lt;li&gt;install S/SU/SULLR/IO-Socket-SSL-1.30.tar.gz&lt;/li&gt;
&lt;li&gt;install GBARR/Authen-SASL-2.12.tar.gz&lt;/li&gt;
&lt;li&gt;install C/CW/CWEST/Net-SMTP-SSL-1.01.tar.gz&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And finally here is the rewritten script!
&lt;a href=&quot;http://gist.github.com/184654&quot;&gt;http://gist.github.com/184654&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>BarCampGR</title>
    <link href="https://jonmagic.com/posts/barcampgr/"/>
    <updated>2009-08-22T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/barcampgr/</id>
    <content type="html">&lt;p&gt;Just wanted to post a little something while I’m still here at &lt;a href=&quot;http://barcampgr.org/&quot;&gt;BarCampGR&lt;/a&gt;, an attendee driven conference. Its been great fun, as you can see from the many &lt;a href=&quot;http://twitter.com/#search?q=%23barcampgr&quot;&gt;posts to twitter&lt;/a&gt;…&lt;/p&gt;
&lt;h3 id=&quot;note-to-those-who-attended-my-talk-on-smoking-meats%2C-here-are-some-great-links%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/barcampgr/#note-to-those-who-attended-my-talk-on-smoking-meats%2C-here-are-some-great-links%3A&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Note to those who attended my talk on smoking meats, here are some great links:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://amazingribs.com/&quot;&gt;Amazing Ribs&lt;/a&gt; is the definitive place to learn about smoking ribs. Look at the page about Texas Crutch to find the perfect cooking method.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://getyourgrillon.net/2008/04/21/bite-through-smoked-chicken-skin/&quot;&gt;this chicken recipe&lt;/a&gt; is amazing, just make sure you cut down the salt they use in the brine, &lt;strong&gt;AND&lt;/strong&gt; the rub, by half, or it will be way too salty.&lt;/li&gt;
&lt;li&gt;kind of off topic, but &lt;a href=&quot;http://gist.github.com/129533&quot;&gt;this was a great recipe&lt;/a&gt;, even if it had nothing to do with smoking 😃&lt;/li&gt;
&lt;li&gt;wanna see my original rig? &lt;a href=&quot;http://jonmagic.com/2008/11/1/temperature-time&quot;&gt;check it out&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Subscribe to my &lt;a href=&quot;http://feeds.feedburner.com/jonmagic&quot;&gt;rss feed&lt;/a&gt;, or at least follow me on &lt;a href=&quot;http://twitter.com/jonmagic&quot;&gt;twitter&lt;/a&gt;, if you are interested in smoking, or cooking in general. Oh yeah, I post about tech too.&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Best phone system for a small business, Part 1</title>
    <link href="https://jonmagic.com/posts/best-phone-system-for-a-small-business-part-1/"/>
    <updated>2009-08-16T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/best-phone-system-for-a-small-business-part-1/</id>
    <content type="html">&lt;p&gt;This article is for small business owners, and even better, for their IT guy/gal… If you are looking at upgrading your phone system, and want to upgrade inexpensively but have a clear upgrade path for the future, I’m going to outline how to build what I believe to be the most cost effective, easy to maintain, pbx based phone system available.&lt;/p&gt;
&lt;p&gt;The pbx itself is based on PC hardware, with a special card for interfacing with the telco (ATT, Verizon, etc), and a software stack called &lt;a href=&quot;http://pbxinaflash.net/&quot;&gt;PBX in a Flash&lt;/a&gt;. PBX in a Flash (PiaF) was put together &lt;a href=&quot;http://pbxinaflash.net/about/&quot;&gt;by a few gentlemen&lt;/a&gt; looking for a solid software stack for their telephony needs. Here is what is in the stack:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.centos.org/&quot;&gt;CentOS&lt;/a&gt; for the OS that everything lies on top of.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.asterisk.org/&quot;&gt;Asterisk&lt;/a&gt; for the PBX stack.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.freepbx.org/&quot;&gt;FreePBX&lt;/a&gt; helps in configuring and maintaining the Asterisk configuration.&lt;/li&gt;
&lt;li&gt;Prebuilt scripts, for configuring everything from dhcp to cisco phones&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For phone hardware I’ve used Cisco, Linksys, and &lt;a href=&quot;http://www.aastra.com/&quot;&gt;Aastra&lt;/a&gt;. Aastra seems to be the recommended brand of late, for features, price, and ease of configuration. I’m not a huge fan of the Cisco phones (overpriced and they seem to cripple their SIP firmware), but Cisco’s economical product line, Linksys, makes some great phones.&lt;/p&gt;
&lt;p&gt;Well, there’s the intro for you, if you want to learn more, read on!&lt;/p&gt;
&lt;p&gt;I’ve done phone systems for businesses that only need 2 or 3 phones, and systems for companies with 20+ extensions. I’m comfortable recommending this system for a business with up to 100 extensions, more than that and you might want to look at having dual load balanced servers.&lt;/p&gt;
&lt;p&gt;For this setup I’m going to describe below, we’ve got a business with around 30 employees, 20 of which have their own extensions on the phone system. There is a sales group, support group, and various administrators, as well as production staff.&lt;/p&gt;
&lt;p&gt;Any $400 to $600 PC will work for our base system. 2.0ghz+ Intel or AMD processor, at least 1gb of ram (I put in 2gb since its so cheap). Looking for hardware with a good warranty? Check out my company &lt;a href=&quot;https://web.archive.org/web/2012/http://www.sabretechllc.com&quot;&gt;SabreTech Consulting LLC&lt;/a&gt; for some great PC’s. We ship anywhere in the US (and actually, a lot of our PC’s are overseas as well, thru an associate of ours).&lt;/p&gt;
&lt;p&gt;Let me back up for a second and explain the two ways we can get “dial tone” to our phone system (i.e. be able to make calls to the outside world).&lt;/p&gt;
&lt;p&gt;Way #1, use land lines thru your local telco, for example ATT or Verizon.
Way #2, use voip trunks thru any of hundreds of carriers, this method requires a NICE SOLID internet connection.&lt;/p&gt;
&lt;p&gt;Depending on your area and telco providers, it may or may not be more cost effective to use land lines thru the telco. These days I’ve found that its usually cost effective to have enough land lines, with “unlimited” long distance/local packages on them, for your average use (sum of the number of lines you use every minute of the day, divided by the number of minutes they are in use), and then voip trunks for “peak” times when you need Just A Little More, and for international calls.&lt;/p&gt;
&lt;p&gt;So, we’ve figured out that our average use is 4 to 6 lines in use at any given minute (this is just calls to the outside world, does not include internal calls, i.e. extension to extension). So we want to get 6 lines with unlimited local and long distance packages, which ends up costing about $456 a month. So how do we get these phone lines into our phone system?&lt;/p&gt;
&lt;p&gt;Ok, time to step back again and explain the two ways the phone company can get us a line, digital or analog.&lt;/p&gt;
&lt;p&gt;Analog lines are the ones we had when we were growing up, you know, the phone on your wall in the kitchen 😃 These analog lines are also called &lt;a href=&quot;http://en.wikipedia.org/wiki/Plain_old_telephone_service&quot;&gt;pots lines&lt;/a&gt;.
Digital lines, a.k.a. &lt;a href=&quot;http://en.wikipedia.org/wiki/Primary_rate_interface&quot;&gt;PRI’s&lt;/a&gt;, usually come in bundles of 23. In some areas you can get “partial” PRI’s, and if you can in your area, and the price is right, DO IT…  Digital lines will be better quality and give fewer headaches than analog lines. The nice thing about digital lines is they either WORK or they DON’T WORK, there’s not much in-between. Analog lines on the other hand, can have a myriad of problems, including dropped calls, static, etc. Analog lines can work, even if the connection is crappy, and therefore its harder to convince the telco that there might be a problem with the line.&lt;/p&gt;
&lt;p&gt;So, I want some lines from my telco, but I need to get them INTO the phone system! My absolute favorite company for doing this is &lt;a href=&quot;http://www.rhinoequipment.com/&quot;&gt;Rhino Equipment&lt;/a&gt;. They make a series of analog and digital interface cards. These cards ARE NOT CHEAP, BUT they are worth every penny and more. In fact, I would pay twice the price they charge for them, and here is why: they have the best tech support I have ever used in my life. Let me repeat that. THEY HAVE THE BEST TECH SUPPORT ON THE PLANET. These guys have helped me time and time again, always courteous and patient. On one job they worked with me for 3 days trying to troubleshoot dropped calls, and said on day 2 that it wasn’t their equipment, but instead the phone company, but they stuck in there RIGHT TO THE END. They kept helping me, even after they knew it was the phone company and not their equipment causing problems, and if it weren’t for them, I never could have convinced the phone company to get their act together and fix the lines.&lt;/p&gt;
&lt;p&gt;For most small businesses, where I can’t get a PRI, only pots lines, I use the &lt;a href=&quot;http://www.rhinoequipment.com/R8FXXcard.html&quot;&gt;Rhino R8FXX-EC card&lt;/a&gt;. It can support up to 4 fxo (or fxs) modules on it. Each fxo module can handle 2 pots lines from the telco. This card has built in echo cancellation, just one more reason its worth every penny. For this example, since we’re going to have 6 lines, I need to get the Rhino card with 3 modules on it.&lt;/p&gt;
&lt;p&gt;Ok, we’ve got our PC, we’ve got our interface card to interface with the telco, now we just need to pick a phone model to get everyone. I’m going to have to go with &lt;a href=&quot;http://nerdvittles.com/index.php?p=207&quot;&gt;this recommendation&lt;/a&gt;, the &lt;a href=&quot;http://www.aastra.com/cps/rde/xchg/SID-3D8CCB6A-BC5ACAC2/04/hs.xsl/19703.htm&quot;&gt;Aastra 57i&lt;/a&gt;. I have yet to get this particular model in to try myself, but I trust Ward Mundy with my life, so what he says, goes 😃&lt;/p&gt;
&lt;p&gt;Well, two pages in and I’ve decided to split this into a multi part article. We’ll call this Part I. Please keep checking back for Part II, where I’ll cover installing and configuring the software stack and your Rhino card.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Family Ribs</title>
    <link href="https://jonmagic.com/posts/family-ribs/"/>
    <updated>2009-06-28T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/family-ribs/</id>
    <content type="html">&lt;p&gt;My cousin and his wife Karen (i.e. Family) are visiting us this weekend.
My cuz is an artist, an &lt;a href=&quot;http://www.theicestudio.com/&quot;&gt;ice sculptor&lt;/a&gt; and he also &lt;a href=&quot;http://img30.yfrog.com/i/woz.jpg/&quot;&gt;works with sand&lt;/a&gt;! This is the second year he has visited us while doing work up in Niles MI, but the first time Karen has come to visit us. In fact, it’s the first time Karen and my wife have met 😃&lt;/p&gt;
&lt;p&gt;Anyways, one of the means I used to entice Karen to visit us was my incessant twittering about food, mwahahaha…&lt;/p&gt;
&lt;p&gt;Tomorrow Natalie is working, and Stephan is exhausted, so we’ll miss church this week while I get things ready for a big lunch.&lt;/p&gt;
&lt;p&gt;I’ll probably be getting up at around 7am to start the smoker(s) (I’ve converted my grill to a smoker too), and be occupied with that until close to 2pm when Nat gets home from work, and hopefully the food is ready. I’m making ribs! St Louis cut spare ribs and baby back ribs!&lt;/p&gt;
&lt;p&gt;Karen was gracious enough to help me with the rib prep today. Cutting the spare ribs down to St Louis style ribs and making the rub and then getting all the racks and extra bits seasoned and in the fridge. We (well me at least) had a great time hanging out, talking about everything from their “MONUMENTAL WEDDING!” to when Natalie and I were thinking about starting a family.&lt;/p&gt;
&lt;p&gt;Since moving to Indiana Natalie and I have become very very close, but we haven’t made too many friends, so it was really nice to talk to someone else at length, and just hang out all day, being silly, going on a road trip with the dogs (four of them!) to see Stephan, and of course working on the ribs together.&lt;/p&gt;
&lt;p&gt;Well, I’ll make sure and post tons of pics tomorrow! I’m really looking forward to this!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Rapid Onsite Software Development</title>
    <link href="https://jonmagic.com/posts/rapid-onsite-software-development/"/>
    <updated>2009-06-24T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/rapid-onsite-software-development/</id>
    <content type="html">&lt;p&gt;My uncle has been bugging me to help him with writing some software for awhile now, and this last weekend he sent me another email with a new idea, to help him in his business. I had some time available this week, so I decided to drive down to his shop and try something. My goal was to take his simple idea, boil it down to its essence, and write the whole application in a day using &lt;a href=&quot;http://www.rubyonrails.com/&quot;&gt;Rails&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To prepare myself I started working on &lt;a href=&quot;http://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;TDD&lt;/a&gt; again, using &lt;a href=&quot;http://thoughtbot.com/projects/shoulda/&quot;&gt;shoulda&lt;/a&gt; and &lt;a href=&quot;http://thoughtbot.com/projects/factory_girl&quot;&gt;factory_girl&lt;/a&gt;. I also built my own version of &lt;a href=&quot;http://github.com/fudgestudios/bort/tree/master&quot;&gt;bort&lt;/a&gt; from the ground up, called &lt;a href=&quot;http://github.com/jonmagic/pudding/&quot;&gt;pudding&lt;/a&gt; (it has a couple flavors, including &lt;a href=&quot;http://github.com/jonmagic/pudding/tree/vanilla&quot;&gt;vanilla&lt;/a&gt; and &lt;a href=&quot;http://github.com/jonmagic/pudding/tree/tapioca&quot;&gt;tapioca&lt;/a&gt;). I tried to find the right mix of features to give myself a running start when I arrived onsite.&lt;/p&gt;
&lt;p&gt;I arrived at 8:30am this morning and started programming at 9am. At first things were going fairly well, building my models out using TDD went fast, and I was rolling along nicely on writing my controllers using TDD when I hit a wall, aka, lack of knowledge on my part. After hitting this wall for 45 minutes I finally gave up on TDD and just went back to my old way of doing things, i.e. no testing.&lt;/p&gt;
&lt;p&gt;I was back on a roll again, using my &lt;a href=&quot;https://github.com/jonmagic/webapp_gui/tree&quot;&gt;osx theme&lt;/a&gt; for the admin interface, and &lt;a href=&quot;http://www.blueprintcss.org/&quot;&gt;blueprint&lt;/a&gt; for the css reset, typography, and layout on the technician facing part of the application (the part that will be used the most).&lt;/p&gt;
&lt;p&gt;Things were going along nicely until I ran into issues with the way I was doing ajax modals, via &lt;a href=&quot;http://jquery.com/demo/thickbox/&quot;&gt;thickbox&lt;/a&gt;. I’d already implemented quite a bit using thickbox, when I decided I needed to start over on my modals using a different library. So far I think I’m gonna use &lt;a href=&quot;http://dev.iceburg.net/jquery/jqModal/&quot;&gt;jqModal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, at 4:30pm I called it quits for the day, realizing my “app in a day” dream was not gonna happen, although I believe I’m about a 1/3rd of the way there, which isn’t too bad.&lt;/p&gt;
&lt;h3 id=&quot;lessons-learned%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/rapid-onsite-software-development/#lessons-learned%3F&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Lessons learned?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;I need to work quite a bit more on testing, I need to know it like the back of my hand&lt;/li&gt;
&lt;li&gt;I need to have a sample controller built out in my pudding apps, so I can do a bit of copy/paste when building my controllers&lt;/li&gt;
&lt;li&gt;It would also be nice to include my osx theme, and blueprint theme in my pudding apps&lt;/li&gt;
&lt;li&gt;I need to get better at jQuery, and find the best plugins for my different needs&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Preparing Dinner for Natalie and lil&#39;sis TweetWhiskey Glazed Pork ChopsCountry Style Tomatoes</title>
    <link href="https://jonmagic.com/posts/preparing-dinner-for-natalie-and-lilsis-tweetwhiskey-glazed-pork-chopscountry-style-tomatoes/"/>
    <updated>2009-06-17T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/preparing-dinner-for-natalie-and-lilsis-tweetwhiskey-glazed-pork-chopscountry-style-tomatoes/</id>
    <content type="html">&lt;h2 id=&quot;whiskey-glazed-pork-chops&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/preparing-dinner-for-natalie-and-lilsis-tweetwhiskey-glazed-pork-chopscountry-style-tomatoes/#whiskey-glazed-pork-chops&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Whiskey Glazed Pork Chops&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1/2 cup Jack Daniel’s Tennessee whiskey&lt;/li&gt;
&lt;li&gt;1/2 apple cider&lt;/li&gt;
&lt;li&gt;2 tablespoons of light brown sugar&lt;/li&gt;
&lt;li&gt;1 tablespoon dijon mustard&lt;/li&gt;
&lt;li&gt;1/8 teaspoon of cayenne pepper&lt;/li&gt;
&lt;li&gt;1/2 teaspoon vanilla extract&lt;/li&gt;
&lt;li&gt;4 teaspoons cider vinegar&lt;/li&gt;
&lt;li&gt;4 bone-in, center-cut pork chops, about 1 inch thick&lt;/li&gt;
&lt;li&gt;2 teaspoons vegetable oil&lt;/li&gt;
&lt;li&gt;salt and pepper&lt;/li&gt;
&lt;li&gt;1 tablespoon unsalted butter&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Whisk together the whiskey, cider, brown sugar, mustard, cayenne, vanilla, and 2 teaspoons of vinegar. Marinate the chops in a quarter (1/4) of this liquid, set aside the rest.&lt;/li&gt;
&lt;li&gt;Remove chops from the bag, pat dry with paper towels, and discard marinade. Heat up oil in a large skillet over medium-high heat until just starting to smoke. Season the chops with salt and pepper, then throw them in the pan and brown both sides, 2-3 minutes per side. Transfer chops to a plate and cover tightly with foil.&lt;/li&gt;
&lt;li&gt;Add the rest of the whiskey mix into the skillet and bring to a boil, scraping up any brown bits from the meat. Cook until reduced to a thick glaze, 3 to 5 minutes. Reduce heat to medium-low and drain any juices from the chops plate into the mix. Add 2 teaspoons of cider vinegar, whisk in the butter, and simmer until thick and sticky, 2 to 3 minutes. Remove pan from heat.&lt;/li&gt;
&lt;li&gt;Return chops to skillet and let them rest in the pan until sauce clings to them, turning to coat both sides. Leave in there while they finish cooking, about 5 minutes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;country-style-tomatoes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/preparing-dinner-for-natalie-and-lilsis-tweetwhiskey-glazed-pork-chopscountry-style-tomatoes/#country-style-tomatoes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Country Style Tomatoes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;4 large tomatoes&lt;/li&gt;
&lt;li&gt;8oz of cream cheese&lt;/li&gt;
&lt;li&gt;1/2 teaspoon dried basil&lt;/li&gt;
&lt;li&gt;1 garlic clove, minced&lt;/li&gt;
&lt;li&gt;1/4 teaspoon of salt&lt;/li&gt;
&lt;li&gt;flour&lt;/li&gt;
&lt;li&gt;bread crumbs&lt;/li&gt;
&lt;li&gt;1 egg&lt;/li&gt;
&lt;li&gt;1 tablespoon of milk&lt;/li&gt;
&lt;li&gt;3 tablespoons of butter&lt;/li&gt;
&lt;li&gt;3 tablespoons of olive oil&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Cut each tomato into four thick slices, and then place on paper towels to drain. In a small bowl beat the cream cheese, basil, garlic and salt until blended. Spread mixture onto half the tomato slices and then top with remaining slices.&lt;/li&gt;
&lt;li&gt;Place flour and bread crumbs in separate pie pans, in another pan whisk egg and milk. Coat top and bottom of each tomato stack with flour, then egg mixture, and then bread crumbs.&lt;/li&gt;
&lt;li&gt;In a large skillet, heat butter and oil over medium-high heat. Fry tomato sandwiches in batches for 3-4 minutes on each side or until golden brown. Drain on paper towels and serve.&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  
  <entry>
    <title>Configuring PBX in a Flash to use Rhino cards</title>
    <link href="https://jonmagic.com/posts/configuring-pbx-in-a-flash-to-use-rhino-cards/"/>
    <updated>2009-06-02T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/configuring-pbx-in-a-flash-to-use-rhino-cards/</id>
    <content type="html">&lt;p&gt;If you are using a &lt;a href=&quot;http://www.rhinoequipment.com/&quot;&gt;Rhino Equipment card&lt;/a&gt; as your PSTN or digital interface to the telco, and need help setting it up on your Asterisk-based PBX, look no further!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://docs.google.com/View?id=atnp7jn5zpr_95fn6n8bc6&quot;&gt;This google doc&lt;/a&gt; has just the instructions you need. (Thanks to James at Rhino for these great instructions!)&lt;/p&gt;
&lt;p&gt;Also, as far as telco cards go, I couldn’t recommend anyone better than &lt;a href=&quot;http://www.rhinoequipment.com/&quot;&gt;Rhino&lt;/a&gt;. Their cards are great, and their technical support is the best I’ve ever had from any company, EVER. They are, simply put, amazing at what they do.&lt;/p&gt;
&lt;p&gt;Oh yeah, when it comes to open source PBX platforms, &lt;a href=&quot;http://www.pbxinaflash.com/&quot;&gt;PBX in a Flash&lt;/a&gt; is the best I’ve found. I’ve tried Asterisk@Home, Trixbox, and a couple others. PiaF is easy to set up, clean, and simple.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Evolution of a twitter client</title>
    <link href="https://jonmagic.com/posts/evolution-of-a-twitter-client/"/>
    <updated>2009-05-22T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/evolution-of-a-twitter-client/</id>
    <content type="html">&lt;p&gt;One of my clients wants his employees to be able to use Twitter, but there were some strict requirements involved, and I couldn’t find a Twitter client for Windows that met all of those requirements, so I decided to write my own Twitter client.&lt;/p&gt;
&lt;p&gt;I’m modeling it after Tweetie for OSX, of course (in look and function). I know Ruby best, so I decided to use &lt;a href=&quot;http://whytheluckystiff.net/&quot;&gt;_why’s&lt;/a&gt; &lt;a href=&quot;http://shoooes.net/&quot;&gt;Shoes&lt;/a&gt; and &lt;a href=&quot;http://railstips.org/&quot;&gt;John Nunemaker’s&lt;/a&gt; &lt;a href=&quot;http://github.com/jnunemaker/twitter/tree/master&quot;&gt;twitter gem&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For those interested in writing a Twitter client and using Shoes, or who like to see the evolution of an app, be sure to check out this article.&lt;/p&gt;
&lt;p&gt;This article is going to be updated as I write this app, but I just wanted to start with a slideshow of the evolution of the app so far.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>What IT guys do when their bored</title>
    <link href="https://jonmagic.com/posts/what-it-guys-do-when-their-bored/"/>
    <updated>2009-05-21T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/what-it-guys-do-when-their-bored/</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://vimeo.com/4765490&quot;&gt;What IT guys do when their bored&lt;/a&gt; from
&lt;a href=&quot;http://vimeo.com/user1789405&quot;&gt;JonMagic&lt;/a&gt; on &lt;a href=&quot;http://vimeo.com/&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>First time smoking ribs</title>
    <link href="https://jonmagic.com/posts/first-time-smoking-ribs/"/>
    <updated>2009-05-16T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/first-time-smoking-ribs/</id>
    <content type="html">&lt;p&gt;Nat and I smoked pork spare ribs over this Memorial weekend, and they were so yummy.&lt;/p&gt;
&lt;p&gt;Here is a picture of the rub we made, definitely too intense we found out. We will put together a much simpler one next time. We put the rub on them the night before.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://bit.ly/v02eI&quot;&gt;See the recipe here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We smoked the ribs for about 5 hours at 205 to 225 degrees Fahrenheit in my vertical water smoker.&lt;/p&gt;
&lt;p&gt;Here was my smoker setup.&lt;/p&gt;
&lt;p&gt;After smoking I wrapped them in foil, then wrapped in a warm wet towel, and threw in a cooler for an hour to rest. Finally we threw them on the grill for 2 to 4 minutes, some with just the dry rub they’d marinated and smoked in, and the rest I threw some store bought bbq sauce on.&lt;/p&gt;
&lt;p&gt;Natalie made baked beans and potato salad, so we had quite a feast 😃&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Things we’ll do differently next time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;simpler rub, and less of it&lt;/li&gt;
&lt;li&gt;3-2-1 method of cooking, &lt;a href=&quot;http://www.wyntk.us/food/3-2-1-rib-method.shtml&quot;&gt;see here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;home made bbq sauce&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Integrating with Quickbooks</title>
    <link href="https://jonmagic.com/posts/integrating-with-quickbooks/"/>
    <updated>2009-04-23T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/integrating-with-quickbooks/</id>
    <content type="html">&lt;p&gt;If you are a software developer working on software for small to medium businesses, then there is a 70% chance (my unscientific calculation) that you’ll run into Quickbooks at some point.&lt;/p&gt;
&lt;p&gt;If you want to integrate with Quickbooks, and especially if you are a developer using ruby, then this post will point you in the right direction for getting things done. So please, read on 😃&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DISCLAIMER:&lt;/strong&gt; I am a former associate of Daniel (and &lt;a href=&quot;http://www.behindlogic.com/&quot;&gt;BehindLogic&lt;/a&gt;) and I got a freebie for writing this post (which is cool cuz I was gonna write it anyway, but don’t tell him)…&lt;/p&gt;
&lt;p&gt;I’ve been working on writing &lt;a href=&quot;http://jonmagic.com/programming/suite&quot;&gt;software&lt;/a&gt; to manage our small IT consultancy, &lt;a href=&quot;https://web.archive.org/web/2012/http://www.sabretechllc.com&quot;&gt;SabreTech Consulting LLC&lt;/a&gt; and the time came to be able to integrate with our accounting package, Quickbooks. Awhile back we had tried, unsuccessfully, and so I was not looking forward to it this time around.&lt;/p&gt;
&lt;p&gt;But, a friend of mine has been working on writing a &lt;a href=&quot;http://www.behindlogic.com/&quot;&gt;Quickbooks gem&lt;/a&gt; and recently released it to the wild, so I thought I would take a crack at the problem again.&lt;/p&gt;
&lt;p&gt;After getting the gem from him ($199) and the http adapter to sit on our PC that runs quickbooks ($25) I was up and running within minutes. I included the gem in my rails app, fired up my app console, and started creating QB objects and saving them.&lt;/p&gt;
&lt;p&gt;In about 5 hours of work last week I was able to build an interface to easily link clients in Suite to clients in Quickbooks AND make it so when you create a new client in Suite it can automatically create the client in Quickbooks, and populate the phone/email/address fields. Having completed this in such a short time I was feeling pretty good! Working with Quickbooks wasn’t a hassle anymore, so I decided that this week I would tackle turning our completed tickets in Suite (work orders) into invoices in Quickbooks.&lt;/p&gt;
&lt;p&gt;In just 2 days (really fast for me, I’m a slow slow slow programmer) I had wired up an Invoice model in my rails app, had it creating an invoice in quickbooks and putting in the line items for labor, with quantities and descriptions, setting the thank you message at the bottom of the invoice, and setting the “IsToBePrinted” field so that our manager can just click on File &amp;gt; Print Forms &amp;gt; Invoices in Quickbooks and turn all those invoices into paper 😃&lt;/p&gt;
&lt;p&gt;Basically I was able to cut down 3 to 5 minutes of work (for our manager) to a button press and 20 to 60 seconds of server work. That is a time savings (via integration) that most businesses would kill to have.&lt;/p&gt;
&lt;p&gt;Now, while I’m super excited about all this, there were some downers (please fix these Dan!):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Documentation is very sparse and sometimes incorrect, I’ve actually offered to help him on it&lt;/li&gt;
&lt;li&gt;There are some bugs in the gem. One I found was when creating an invoice and setting the quantity field for a line item, it wouldn’t accept a float, only integers. Daniel replied to my emails within 12 hours, and showed me what to fix in the gem, and said he would fix it soon in the gem and re-release the gem to everyone who had bought it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All said and done, I highly recommend the &lt;a href=&quot;http://www.behindlogic.com/&quot;&gt;Quickbooks gem by Daniel Parker of BehindLogic&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Running Mephisto (and other Rails apps) on Site5</title>
    <link href="https://jonmagic.com/posts/running-mephisto-and-other-rails-apps-on-site5/"/>
    <updated>2009-04-20T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/running-mephisto-and-other-rails-apps-on-site5/</id>
    <content type="html">&lt;p&gt;There are a few steps in getting the latest Mephisto (0.8.2 at the time of this writing) working on the shared host &lt;a href=&quot;http://www.site5.com/&quot;&gt;Site5&lt;/a&gt;. As I’m writing this Site5 is upgrading all their servers to Ruby 1.8.7, Rails 2.2.2, RubyGems 1.3.1, and Mysql 5.0. Thanks to everyone at Site5 that helped, &lt;a href=&quot;http://twitter.com/BenAtSite5&quot;&gt;Ben&lt;/a&gt;, Beau, and the guy I talked to today (forgot his name). Continue reading for the steps I/we had to take to get things running properly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; Please make sure to update your .htaccess, Site5 now supports mod_rails on most, if not all of their servers.&lt;/p&gt;
&lt;h3 id=&quot;get-your-own-gems-repository-working&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/running-mephisto-and-other-rails-apps-on-site5/#get-your-own-gems-repository-working&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Get your own gems repository working&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;ssh to your account and in &lt;code&gt;~/&lt;/code&gt; create a gems dir.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; gems&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;create a .gemrc file in &lt;code&gt;~/&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; ~/.gemrc&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;paste the following in (changing username to be your user)&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;gemhome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /home/username/gems
&lt;span class=&quot;token key atrule&quot;&gt;gempath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; /home/username/gems
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; /usr/lib/ruby/gems/1.8&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;edit (or create) .bash_profile in &lt;code&gt;~/&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; ~/.bash_profile&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;paste the following (changing username to be your user)&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;GEM_PATH&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/home/username/gems:/usr/lib/ruby/gems/1.8
&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;GEM_HOME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/home/username/gems&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now you should be able to run &lt;code&gt;gem environment&lt;/code&gt; and see the correct values.&lt;/p&gt;
&lt;h3 id=&quot;downloading-mephisto-and-getting-it-setup.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/running-mephisto-and-other-rails-apps-on-site5/#downloading-mephisto-and-getting-it-setup.&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Downloading Mephisto and getting it setup.&lt;/h3&gt;
&lt;p&gt;I downloaded the latest release of Mephisto from &lt;a href=&quot;http://mephistoblog.com/download&quot;&gt;http://mephistoblog.com/download&lt;/a&gt;, version 0.8.2 Drax Fixes. Once I had it on my dev machine I scp’d it up to Site5. There I created an apps dir in &lt;code&gt;~/&lt;/code&gt; on my Site5 account, and untarred mephisto there. I renamed the dir to &lt;code&gt;mephisto_0.8.2&lt;/code&gt; and got to work on configuring stuff. First I copied &lt;code&gt;config/database.example.yml&lt;/code&gt; to &lt;code&gt;config/database.yml&lt;/code&gt;, went in and deleted all the extra lines, and just configured what I needed. I like to configure my development database, and then for the production one just have it point at the same settings like so:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;development&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mysql
  &lt;span class=&quot;token key atrule&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; username_database
  &lt;span class=&quot;token key atrule&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; username_dbuser
  &lt;span class=&quot;token key atrule&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; password
  &lt;span class=&quot;token key atrule&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; localhost
  &lt;span class=&quot;token key atrule&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; utf8

&lt;span class=&quot;token key atrule&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mysql
  &lt;span class=&quot;token key atrule&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; username_testdatabase
  &lt;span class=&quot;token key atrule&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; username_dbtestuser
  &lt;span class=&quot;token key atrule&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; password
  &lt;span class=&quot;token key atrule&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; localhost
  &lt;span class=&quot;token key atrule&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; utf8

&lt;span class=&quot;token key atrule&quot;&gt;production&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  development&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve been getting into testing stuff more lately, so I went ahead and configured a test database as well. Remember back at the beginning how we had to setup our own spot for gems? Well now we need to tell this application where to look for those gems, and put our app into production mode. &lt;code&gt;nano config/environment.rb&lt;/code&gt; and set the top five lines to look like this (leave everything else alone in this file, oh, and make sure to replace username with your user):&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Be sure to restart your web server when you modify this file.&lt;/span&gt;
&lt;span class=&quot;token constant&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&#39;GEM_PATH&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/home/username/gems:/usr/lib/ruby/gems/1.8&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Uncomment below to force Rails into production mode when&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# you don&#39;t control web/app server and can&#39;t set it the proper way&lt;/span&gt;
&lt;span class=&quot;token constant&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&#39;RAILS_ENV&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&#39;production&#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;preparing-dependencies-and-tell-apache-what-to-do-with-requests!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/running-mephisto-and-other-rails-apps-on-site5/#preparing-dependencies-and-tell-apache-what-to-do-with-requests!&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Preparing dependencies and tell Apache what to do with requests!&lt;/h3&gt;
&lt;p&gt;At this point you’ll have to run the following commands inside your &lt;code&gt;mephisto&lt;/code&gt; dir to get our dependencies ready.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;rake config/initializers/session_store.rb
rake gems:install
rake db:bootstrap&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;THE FOLLOWING .htaccess STUFF IS OBSOLETE, PLEASE JUMP AHEAD&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once you’ve got that done we’re almost there! The next to last thing is add an &lt;code&gt;.htaccess&lt;/code&gt; file to our public folder so that Apache knows to execute &lt;code&gt;dispatch.fcgi&lt;/code&gt; when a request comes in. So &lt;code&gt;nano public/.htaccess&lt;/code&gt; and paste the following:&lt;/p&gt;
&lt;pre class=&quot;language-apache&quot;&gt;&lt;code class=&quot;language-apache&quot;&gt;Options +FollowSymLinks +ExecCGI
RewriteEngine On
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
RewriteCond %{HTTP_ACCEPT} application/xrdsxml
RewriteCond %{HTTP_ACCEPT} !application/xrdsxml&#92;s*;&#92;s*q&#92;s*=&#92;s*0(&#92;.0{1,3})?&#92;s*(,|$)
ErrorDocument 500 &quot;&lt;h2&gt;Application error&lt;/h2&gt;Rails application failed to start properly&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;OK, NOW THAT Site5 SUPPORTS mod_rails MAKE YOUR .htaccess LOOK LIKE THIS&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-apache&quot;&gt;&lt;code class=&quot;language-apache&quot;&gt;PassengerEnabled on&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Last but not least we need to go to &lt;code&gt;~/&lt;/code&gt; and rename &lt;code&gt;public_html&lt;/code&gt; to &lt;code&gt;public_html_old&lt;/code&gt; and then create a symlink like so:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; ~/apps/mephisto_0.8.2/public public_html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it! Open your browser and try to access your site. Things should be working at this point.&lt;/p&gt;
&lt;p&gt;If it returns &amp;quot;Rails application failed to start properly” start looking to make sure you have all the gems you need. One thing I like to do is from my mephisto dir, run &lt;code&gt;./script/console&lt;/code&gt; and do a few db lookups, then if that works I run &lt;code&gt;./script/server -e production&lt;/code&gt; and then in a second ssh session to my Site5 account I’ll do a &lt;code&gt;curl http://localhost:3000/&lt;/code&gt; to see what it returns. Often you can see the exact error doing it this way, and fix the problem!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OTHER NOTES:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do not install image_science gem even though mephisto works with it now. Site5 does not install freeimage on their servers, only imagemagick, and the Rmagick gem, so just go with those.&lt;/li&gt;
&lt;li&gt;You could automate a lot of this with Capistrano, but if you are only doing it once, why bother? I use Capistrano in a lot in other instances, but was just lazy here 😃&lt;/li&gt;
&lt;li&gt;Make sure your permissions on your public folder and dispatch.fcgi are set to 755&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  
  <entry>
    <title>A little story called fun</title>
    <link href="https://jonmagic.com/posts/a-little-story-called-fun/"/>
    <updated>2009-03-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/a-little-story-called-fun/</id>
    <content type="html">&lt;p&gt;This last weekend I took my wife to Chicago for her birthday, and her best friend flew in from Boston to join us. We had a wonderful weekend, they got to go shopping, we all got to eat amazing food, and I managed to talk them into going to blues and piano joints rather than dance clubs (except for one place that had Jazz upstairs and dancing downstairs).&lt;/p&gt;
&lt;p&gt;Sunday before taking Michelle to the airport we all went to Ikea so Natalie could do SOME MORE shopping 😃 Michelle and I were kinda tired, and bored, so while sitting on a very nice leather couch I suggested we play a game. We would co-write a book, taking turns, using our phones and facebook status. The rules were: no more than 255 characters per post (I think Michelle’s was limited to 140), and no colluding. So basically we didn’t set up the story in any way, it just worked itself out as we went along.&lt;/p&gt;
&lt;p&gt;The game ended up being tremendously fun, and got us through the better part of the day, including an hour or two of the time Michelle had to spend in the airport, because her flight was delayed. Because we were doing this on facebook, and it would only make sense if you were friends with BOTH of us and saw the updates coming in sync, a lot of people thought we were absolutely off our rockers. In fact, this comment to Michelle from her friend pretty much sums up what it must have looked like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;DeAnna: sometimes i read your status updates and think you are on crack.
i think a crackberry is bad for someone already addicted to crack….&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;p.s. i would have called you this weekend, but clearly you are having fun with your bffs. and taking lots of crack. so later this week?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you were one of those people only getting half the story, I’ve included the whole thing if you click thru to read the rest of this post 😃 Enjoy&lt;/p&gt;
&lt;h3 id=&quot;the-beginning&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-little-story-called-fun/#the-beginning&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Beginning&lt;/h3&gt;
&lt;p&gt;2:20pm Jonathan woke to the phone ringing. Ok ok he thought, and slid his finger across the face of the iphone to answer it&lt;/p&gt;
&lt;p&gt;2:22pm Michelle was on the other end of the line, “That’s it Jonny-Boy, we’re done for”&lt;/p&gt;
&lt;p&gt;2:25pm Jonathan jerked the rest of the way to consciousness. “what!” he screamed! “You didn’t stop the package in time?”&lt;/p&gt;
&lt;p&gt;2:28pm Michelle , stunned by Jon’s reaction lost composure &amp;quot; ME?? ME not stop the package in time!!! since when was that my responsibility you…hold on, another call&amp;quot;&lt;/p&gt;
&lt;p&gt;2:49pm Jonathan started racking his brain, when had he ever taken responsibility… Didn’t matter, the cat was almost out of the bag, and there was nothing he could do about it, short of storming the courier service and going Jack Bauer on em&lt;/p&gt;
&lt;p&gt;2:52pm Michelle clicked back onto the line “sorry about that it was Z and he is &lt;strong&gt;NOT&lt;/strong&gt; happy we’ve gotta get down there like now” she finished as she climbed out of bed&lt;/p&gt;
&lt;p&gt;3:01pm Jonathan said “meet you in 15, corner of le salle and ohio” and he hung up. Throwing some clothes on he grabbed the already packed bag and bolted for the door. He never looked back, but couldn’t help but think as he raced down the steps that that was the last time he would see his apartment on the north side&lt;/p&gt;
&lt;p&gt;3:05pm Michelle jumped into her Mini that the driver had brought around “thank you marcus” she umbled as she climbed in and slammed on the gas.&lt;/p&gt;
&lt;p&gt;3:12pm Jonathan neared the corner, and saw her mini zipping east on Ohio towards him. To his left he heard an suv accelorate, and instantly knew things were about to go very wrong&lt;/p&gt;
&lt;p&gt;3:17pm Michelle saw Jon walking down the street and thought “damn hippies” and threw the wheel to the right and slammed on the breaks inches in front of him,he looked worried.&lt;/p&gt;
&lt;p&gt;3:41pm Michelle looked at the silent Jon “hello! what’s wrong with you? you’re not talking now? get in we need to hurry”&lt;/p&gt;
&lt;p&gt;3:39pm Jonathan jumped in and grumbled something about company coming “in like 2 seconds” and that they probably weren’t here to play nice&lt;/p&gt;
&lt;p&gt;3:48pm Michelle looked to the left and saw the &lt;strong&gt;SUV&lt;/strong&gt; reeling around to backtrack at them “ugh. again?” she said throwing the mini into first and peeling out “any idea who?”&lt;/p&gt;
&lt;p&gt;4:02pm Jonathan said &amp;quot;well I’m guessing it’s not one of my ex girlfriends&amp;quot;he twisted his head around and saw three heads through the windshield of the approaching suburban and they definately looked Spanish&lt;/p&gt;
&lt;p&gt;4:04pm Michelle looked at him. “spanish? you think that you can tell someoines exact &lt;strong&gt;NATIONALITY&lt;/strong&gt; from a hundred yards away in a soeeding car? gimmee a break!”&lt;/p&gt;
&lt;p&gt;4:05pm Michelle kept her eyes on the road, “look let’s just get to Z without incident and figure out who the hell they are then. got your passport?”&lt;/p&gt;
&lt;p&gt;4:08pm Jonathan said “which one?any idea where we might be going? I just hope Z gets us outta here sooner rather than later. And I don’t care if I ever see Chicago again”&lt;/p&gt;
&lt;p&gt;4:32pm Michelle glanced in the mirror and saw they had lost the &lt;strong&gt;SUV&lt;/strong&gt;, “good question. call Z let’s find out what the hells going on” she said as they pulled up to the terminal&lt;/p&gt;
&lt;p&gt;4:43pm Jonathan picked up his phone and dialed.“z, where we goin’?we gotta get out of here fast!” “Sophia? Ok, whatever.”&lt;/p&gt;
&lt;p&gt;4:50pm Michelle looked at Jon blankly &amp;quot;sophia? really this day keeps getting stranger and stranger. guess we’re the… Walshes then. Lee and Lea brother and sister again. C’mon&lt;/p&gt;
&lt;p&gt;4:57pm Jonathan grabbed the bags and plastered a smile on his face. “you know, the more I think about it, those thugs may have had something to do with an ex, I think her family was connected in certain parts of Europe where the Spanish might have power.”&lt;/p&gt;
&lt;p&gt;5:01pm Michelle laughed and slipped on her glasses “right your long line of European exes… Spanish exes” shaking her head they walked inside ignoring the cries of the bellman&lt;/p&gt;
&lt;p&gt;5:07pm Jonathan stayed cheery as they grabbed their tickets at the lufthansa counter. “Our connections in Frankfurt, maybe we can grab a pint while we’re there.”&lt;/p&gt;
&lt;p&gt;5:17pm Michelle nodded in egar agreement, they quickly passed through security and took two seats in the lounge. just as she was about to nodd off she heard a familar voice&lt;/p&gt;
&lt;p&gt;5:23pm Jonathan didn’t even turn around as Z began to berate them them from where he was seated. “you guys are getting sloppy, someone want to explain why that recording is on it’s way to the PM right now?”&lt;/p&gt;
&lt;p&gt;5:27pm Michelle whipped around “damn it Z! you know if you’d quit hiring rookie couriers we wouldn’t be in this mess! I told you we couldn’t trust that kid”&lt;/p&gt;
&lt;p&gt;5:37pm Jonathan interjected, “I don’t see how this is helping, the damage has been done. All we can hope is that Obama’s staff find the traitors in time and bring the operation down.” “in the meantime I suggest you tell us what our next assignment is.”&lt;/p&gt;
&lt;p&gt;5:42pm Michelle glared at jon for a brief second then decided he was right and looked to Z for the answers &amp;quot;look I dont know anymore than that you both need to be on that plane&lt;/p&gt;
&lt;p&gt;5:47pm Jonathan wondered if this had anything to do with Petrov, it had been 5 years since they last worked together, and hadn’t he gone civ and back to his home country? No matter, the announcement came over the speaker that it was time to board&lt;/p&gt;
&lt;p&gt;5:51pm Michelle gathered her bag and headed to the plane. this wa s always her favorite part- the calm before the storm, the plan before the chase. she couldn wait to land&lt;/p&gt;
&lt;p&gt;5:56pm Jonathan fell asleep before the wheels left the ground, waking only when “sis” shook him because she was bored. “wudda you want?” he grunted at her&lt;/p&gt;
&lt;p&gt;5:59pm Michelle looked down at him. &amp;quot; do you think…no. sorry&amp;quot; he glared at her&amp;quot;what?&amp;quot; he asked annoyed “do you think that Petrov might be involved? I know its crazy but”&lt;/p&gt;
&lt;p&gt;6:03pm Jonathan perked up a bit, “yeah that’s the first thing that came to my mind! But why would he need us? We’re mostly just the Company’s grifters.”&lt;/p&gt;
&lt;p&gt;6:06pm Michelle nodded in excitement, “maybe our time has finally come! I mean we’ve been schleping with intelligence for 6 years, maybe they’re moving us up!”. she babbled&lt;/p&gt;
&lt;p&gt;6:14pm Jonathan snickered, “oh does lanky lea wanna be a double 0?” “that’s so cute”…&lt;/p&gt;
&lt;p&gt;6:21pm Michelle punched Jon in the arm and rolled over to go back asleep secretly hoping that she would be&lt;/p&gt;
&lt;p&gt;6:30pm Jonathan checked their next boarding passes as they exited the plane, “looks like we’ve got about 8 hours to kill. Wanna go to that one place where we met that one guy that one time, you know, the guy with the dog?”&lt;/p&gt;
&lt;h3 id=&quot;the-end&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/a-little-story-called-fun/#the-end&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The End&lt;/h3&gt;
</content>
  </entry>
  
  <entry>
    <title>We have crossed the border.</title>
    <link href="https://jonmagic.com/posts/we-have-crossed-the-border/"/>
    <updated>2009-02-28T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/we-have-crossed-the-border/</id>
    <content type="html">&lt;p&gt;When I first got started in computers professionally (while still in highschool) I never dreamed I would be a partner in a company that did business internationally. Before I tell that story let me give you some background.&lt;/p&gt;
&lt;p&gt;I am a partner in a &lt;a href=&quot;https://web.archive.org/web/2012/http://www.sabretechllc.com&quot;&gt;small IT consultancy&lt;/a&gt; based out of southern Michigan. My first partner (Brad) and I bought SabreTech Consulting LLC from an old friend of mine in the summer of 2005. We’ve been selling and servicing computers for businesses and individuals since then, doing our best to make sure the customer comes first. In 2007 Sam joined us (and became a partner in 2008) and we continued to expand into northern Indiana and Ohio. Business has been great, we’ve even purchased a new (and bigger) building in Michigan and moved our retail location.&lt;/p&gt;
&lt;p&gt;But this week things really got interesting. One of my clients in Hillsdale asked me if I could help his friend in France. I said sure, so he gave me her email address and I setup a meeting. Tuesday her and I skyped, and then started a remote connection so I could fix her computer. How cool is that! SabreTech Remote Connection from Elkhart Indiana to Versailles France 😃&lt;/p&gt;
&lt;p&gt;Later I was bragging about my remote to Sam, and he was kind enough to inform me that one of our clients that buys custom embedded systems from us was sending our equipment all over the world, Canada, Peru, Ireland, and Egypt!&lt;/p&gt;
&lt;p&gt;God has blessed me with an amazing wife, family, business partners, and now an international business.&lt;/p&gt;
&lt;p&gt;Except for putting my back out, it’s been a great week 😃&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Moving to Disqus for comments</title>
    <link href="https://jonmagic.com/posts/moving-to-disqus-for-comments/"/>
    <updated>2009-02-21T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/moving-to-disqus-for-comments/</id>
    <content type="html">&lt;p&gt;I’ve been thinking about using Disqus for awhile now and finally decided to bite the bullet when I realized I just couldn’t get the features I wanted out of Mephisto’s built in comment system.&lt;/p&gt;
&lt;p&gt;Setting &lt;a href=&quot;http://disqus.com/&quot;&gt;Disqus&lt;/a&gt; up on your blog is easy enough, they’ve got automated stuff for the popular hosted blogging platforms, and easy to insert html/js for those of us running our own custom blogging systems, like &lt;a href=&quot;http://mephistoblog.com/&quot;&gt;Mephisto&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you are interested in doing this yourself, read on!&lt;/p&gt;
&lt;p&gt;I wanted to be able to keep the 90+ comments I had already though, and importing didn’t look like it was going to be easy. But then I found &lt;a href=&quot;http://gweezlebur.com/2009/01/05/mephisto-to-disqus.html&quot;&gt;Michael Ivy’s post on importing from Mephisto to Disqus&lt;/a&gt; and got excited at how easy it looked to be. At first I tried using his vanilla script, just filling in the blanks, but quickly realized there were some problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The script didn’t account for your MySQL db having a password&lt;/li&gt;
&lt;li&gt;It gets the article URLs from the article RSS feed, which only returns the last 15 articles by default&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I started tackling the first problem by just changing one line in the script to look like this:&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Sequel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mysql&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:user&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; db_user&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:password&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; db_pass&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:host&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&#39;localhost&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then adding &lt;code&gt;db_pass = &#39;password_here&#39;&lt;/code&gt; to the options stuff above. This kind of worked, except that one of the last lines in the script&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;puts &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Success: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;comment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;author&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; on &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;comment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;errored out on &lt;code&gt;comment.author&lt;/code&gt;, because Sequel isn’t taking into account relationships between models in Mephisto.&lt;/p&gt;
&lt;p&gt;At this point I decided to rework it a little and just use &lt;code&gt;./script/runner&lt;/code&gt; to run the export script, so that I could take full advantage of the Rails app relationships. &lt;a href=&quot;http://gist.github.com/68198&quot;&gt;Here is my updated script&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Things still weren’t quite right though, I either had to modify Mephisto to get back all my articles from the RSS feed, or just use ActiveRecord to pull all that stuff. I decided to edit &lt;code&gt;app/controllers/feed_controller.rb&lt;/code&gt; and remove the &lt;code&gt;:limit =&amp;gt; 15&lt;/code&gt; lines from the three methods at the bottom of that controller. I put them back afterwards 😃&lt;/p&gt;
&lt;p&gt;That should be it, worked great for me, putting all my existing comments into Disqus. Then I just had to modify &lt;code&gt;_comments.liquid&lt;/code&gt;, &lt;code&gt;_entry.liquid&lt;/code&gt;, and &lt;code&gt;layout.liquid&lt;/code&gt; using the built in template editor in Mephisto.&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>A light at the end of the tunnel</title>
    <link href="https://jonmagic.com/posts/a-light-at-the-end-of-the-tunnel/"/>
    <updated>2009-02-08T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/a-light-at-the-end-of-the-tunnel/</id>
    <content type="html">&lt;p&gt;I know it’s not really spring yet, but I can’t help but get my hopes up.
Today around noon we reached 41 degrees, the sun was out, and it just felt amazing outside.&lt;/p&gt;
&lt;p&gt;To celebrate I cleaned out my car 😃&lt;/p&gt;
&lt;p&gt;Then at 3pm we took the dogs for a walk—only Bailey’s second walk, and his first to the park. When we got home, Natalie gave Bailey a bath in the sink while I gave Leo a bath in the tub (first time doing each of them alone; quite a trick). Now I’m grilling outside, with sandals on!&lt;/p&gt;
&lt;p&gt;I’m sure next week the temperature will be back down in the teens, but I can’t help but get excited.&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The car that wasn&#39;t broken</title>
    <link href="https://jonmagic.com/posts/the-car-that-wasnt-broken/"/>
    <updated>2008-12-23T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/the-car-that-wasnt-broken/</id>
    <content type="html">&lt;p&gt;Saturday I had barely returned home to Indiana (from MI) when Natalie called me. She was leaving Target and Kohls in Goshen and wanted to know what I was up to. About a minute into the conversation she said “crap, gotta go, the car just died…” A few minutes later she called back, the car was dead, in the&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Feeling the love</title>
    <link href="https://jonmagic.com/posts/feeling-the-love/"/>
    <updated>2008-12-18T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/feeling-the-love/</id>
    <content type="html">&lt;p&gt;Wow, I must have more friends this year than ever! Several friends called to wish me a happy birthday, I got 10 happy bday text messages, and about 20 emails!&lt;/p&gt;
&lt;p&gt;So anyways, thank you everyone, it was a great birthday. I actually took the day off, the first time since before college I remember not working or taking exams on my bday (except for that one time our prof brought us into class for the exam, and then told us all we got an A and to have a nice day).&lt;/p&gt;
&lt;p&gt;This morning I went Christmas shopping for my wife and my sister. Then this afternoon/evening I smoked a chicken out in the garage. Tina (my lil’sis) showed up a bit after four and she chilled in the garage with me for a couple hours. At 7pm Nat got home from work and we skyped with mom and dad and had a mini-birthday/Christmas party. Since this was our only chance for all of us to get together (virtually) we opened gifts and just had a wonderful time. After that we had an amazing dinner together and watched a movie. To top it off we had Tiramisu that Natalie made… mmm, good.&lt;/p&gt;
&lt;p&gt;In the past I haven’t always looked forward to my birthday. From now on, I think I will.&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Globe Gravity Feed Slicer</title>
    <link href="https://jonmagic.com/posts/globe-gravity-feed-slicer/"/>
    <updated>2008-11-22T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/globe-gravity-feed-slicer/</id>
    <content type="html">&lt;p&gt;This is a post from my old blog that I’ve put up for solidarity. To this day I still get emails from people inquiring about this model slicer 😃&lt;/p&gt;
&lt;p&gt;About a year before my parents headed to South America they started getting rid of most of the stuff they’d accumulated over the years. One of the last things they gifted to Natalie and I was a meat slicer that looked pretty beat up and rusty, but had promise for anyone willing to take the time to take it apart and restore it.&lt;/p&gt;
&lt;p&gt;It’s been sitting in my garage for several months now, collecting dust and more rust. But last weekend, as part of my meat smoking tradition (started about 6 weeks ago, see older posts for fun smoking adventures), I decided I wanted to thinly slice the meat I smoked, and I’m not very good at thinly slicing meat with a knife, so I needed something more.&lt;/p&gt;
&lt;p&gt;I dug the meat slicer out of the corner of the garage, carried it inside (without putting out my back!) and got to work.&lt;/p&gt;
&lt;p&gt;I started by taking it apart, a bit of a challenge the first time, but I’m sure it will be easier in the future now that I know what I’m doing.&lt;/p&gt;
&lt;p&gt;Here are all the individual parts laid out on my counter ready to go into the dishwasher. Oh yeah, I also used a toothbrush and baking soda to scrub the rusty spots and remove about 90% of the rust.&lt;/p&gt;
&lt;p&gt;While the parts were in the dishwasher I started researching this slicer. A Globe Gravity Feed Slicer, Model #150, Serial #223739.&lt;/p&gt;
&lt;p&gt;Couldn’t find much on the internet, other than &lt;a href=&quot;http://www.globeslicers.com/site/default.asp&quot;&gt;Globe’s Website&lt;/a&gt;, and that they are located in Dayton Ohio. They did have contact info on their website though, so I shot them an email asking if they could tell me more about my slicer, and if they had any manuals or accessories for this thing lying around in a warehouse.&lt;/p&gt;
&lt;p&gt;When the parts were done in the dishwasher I put it back together and my did it look good!&lt;/p&gt;
&lt;p&gt;I used it to slice my smoked beef shoulder roast that night (that’s a whole other story, 14 hours on the smoker + 2 hours in the oven crazy) and also sliced some cheese, onion, and bread. It works beautifully, really quite cool. The only problem now is figuring out where to put it 😃&lt;/p&gt;
&lt;p&gt;One last thing: Globe did email me the following Monday, and explained that the current owners bought Globe in 1993, and did not have anything from this old model slicer around. They did tell me though that it was manufactured in 1949.&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>jquery.quickselect.js</title>
    <link href="https://jonmagic.com/posts/jqueryquickselectjs/"/>
    <updated>2008-11-12T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/jqueryquickselectjs/</id>
    <content type="html">&lt;p&gt;Thanks to &lt;a href=&quot;http://behindlogic.com/&quot;&gt;Daniel&lt;/a&gt; for creating a &lt;a href=&quot;http://github.com/dcparker/jquery_plugins/tree/master/quickselect&quot;&gt;nifty new jquery&lt;/a&gt; plugin for me! &lt;a href=&quot;http://github.com/dcparker/jquery_plugins/tree/master/quickselect&quot;&gt;Quickselect&lt;/a&gt; takes select/option tags in HTML and turns them into an input box with live search, and can even use the &lt;a href=&quot;http://rails-oceania.googlecode.com/svn/lachiecox/qs_score/trunk/qs_score.js&quot;&gt;quicksilver.js&lt;/a&gt; for more interesting search results.&lt;/p&gt;
&lt;p&gt;I needed this for Suite, the software I’m writing to manage my company &lt;a href=&quot;https://web.archive.org/web/2012/http://www.sabretechllc.com&quot;&gt;SabreTech&lt;/a&gt;, and I could not for the life of me find a jQuery plugin that did something nifty like this. I had found this &lt;a href=&quot;http://www.pengoworks.com/workshop/jquery/autocomplete.htm&quot;&gt;autocomplete&lt;/a&gt; plugin, and &lt;a href=&quot;http://ejohn.org/blog/jquery-livesearch/&quot;&gt;this live search&lt;/a&gt; plugin (which was actually a rewrite of another plugin by a friend of mine, &lt;a href=&quot;http://orderedlist.com/articles/live-search-with-quicksilver-style-for-jquery&quot;&gt;John Nunemaker&lt;/a&gt;)…&lt;/p&gt;
&lt;p&gt;So I asked Dan to write this up for us yesterday, and this afternoon he found some time and put it together, and guess what, it works &lt;strong&gt;PERFECTLY&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Well, I hope others find this useful…&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Temperature Time</title>
    <link href="https://jonmagic.com/posts/temperature-time/"/>
    <updated>2008-11-01T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/temperature-time/</id>
    <content type="html">&lt;p&gt;Ok, so last weekend I totally botched the brisket. It was slightly edible, more like a steak than anything I guess, but a really, really tough steak. So, rather than give up I’m getting right back on that horse till I can ride thru to the end.&lt;/p&gt;
&lt;p&gt;But, being like my father, I’m not going to settle for mediocre tools. My smoker only came with a simple thermometer in it that says Warm – Ideal – Hot, with no temperatures in degrees on it. I could have just gone and bought an $8 oven thermometer and attached it, but I thought I’d get something a bit cooler and take my time installing it 😃&lt;/p&gt;
&lt;p&gt;It’s easiest to tell this story with pictures, so here goes. This first pic is the Brinkman el-cheapo smoker pre-mods.
&lt;img src=&quot;https://jonmagic.com/images/posts/temperature-time/2993407764_1a8e0dc92a.jpg&quot; alt=&quot;Brinkman el-cheapo smoker&quot; title=&quot;Brinkman el-cheapo smoker&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next up are the tools and parts I used (minus the bandsaw).
&lt;img src=&quot;https://jonmagic.com/images/posts/temperature-time/2992563535_75d78922dd.jpg&quot; alt=&quot;Tools and parts&quot; title=&quot;Tools and parts&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here is the chunk-o-wood I cut with the bandsaw.
&lt;img src=&quot;https://jonmagic.com/images/posts/temperature-time/2992564485_9c3cc23cc9_m.jpg&quot; alt=&quot;Chunk-O-Wood&quot; title=&quot;Chunk-O-Wood&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next I clamped on my chunk of wood and drilled holes for my bolts, then I bolted it on, and finally drilled a couple holes for the thermometer probe.
&lt;img src=&quot;https://jonmagic.com/images/posts/temperature-time/2993411928_e82fc8c222.jpg&quot; alt=&quot;Brinkman hacked&quot; title=&quot;Brinkman hacked&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I inserted the Maverick wireless thermometer probe and put on the grate.
&lt;img src=&quot;https://jonmagic.com/images/posts/temperature-time/2993413134_3ca3c366bf_m.jpg&quot; alt=&quot;You&#39;ve been probed&quot; title=&quot;You&#39;ve been probed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here is a pic from another angle without the grate on.
&lt;img src=&quot;https://jonmagic.com/images/posts/temperature-time/2993414566_b5a7b8fb87.jpg&quot; alt=&quot;silly goose&quot; title=&quot;silly goose&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And last but not least here it is with everything installed and the transmitter and receiver running.
&lt;img src=&quot;https://jonmagic.com/images/posts/temperature-time/2993415836_971e9c1a46.jpg&quot; alt=&quot;We have transmission&quot; title=&quot;We have transmission&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/jonmagic/&quot;&gt;You can see the entire flickr feed here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hopefully tomorrow night I’ll be able to blog a good report about my next brisket. This one is 4 pounds and purchased from a local butcher rather than from the grocery store. Here’s to hoping!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>the Smoker Trifecta</title>
    <link href="https://jonmagic.com/posts/the-smoker-trifecta/"/>
    <updated>2008-10-24T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/the-smoker-trifecta/</id>
    <content type="html">&lt;p&gt;Two weekends ago Natalie bought us a smoker (for smoking meat you silly). This weekend I will complete the trifecta of smoking. The first weekend we smoked pork using &lt;a href=&quot;http://www.foodnetwork.com/recipes/alton-brown/pulled-pork-recipe/index.html&quot;&gt;this recipe&lt;/a&gt; in order to make pulled pork sandwiches, last weekend we smoked a chicken using &lt;a href=&quot;http://getyourgrillon.net/2008/04/21/bite-through-smoked-chicken-skin/&quot;&gt;this recipe&lt;/a&gt; and it was amazing, and this weekend I will complete the trifecta by smoking a beef brisket using &lt;a href=&quot;http://www.thesmokerking.com/page1a.html&quot;&gt;this recipe&lt;/a&gt; (please see the &lt;a href=&quot;http://www.thesmokerking.com/beefrub.html&quot;&gt;rub&lt;/a&gt; and &lt;a href=&quot;http://www.thesmokerking.com/page7b.html&quot;&gt;mop&lt;/a&gt; as well) from the smoker king himself.&lt;/p&gt;
&lt;p&gt;I know, I know, I haven’t done ribs yet. But I will have done pork, chicken, and beef, so I believe we’ll meet the dictionary description of a trifecta:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“a run of three wins or grand events”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Time to start smoking!&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>OSX Styled web gui</title>
    <link href="https://jonmagic.com/posts/osx-styled-web-gui/"/>
    <updated>2008-10-15T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/osx-styled-web-gui/</id>
    <content type="html">&lt;p&gt;I’ll probably get in trouble for this, but I decided to &lt;a href=&quot;http://github.com/jonmagic/webapp_gui/&quot;&gt;release it&lt;/a&gt; anyways… I’ve been working on some software for running my company and needed a nice GUI, implemented in HTML/CSS/JS. I decided, since I prefer using OSX over any other interface, I wanted my web app to look like OSX too.&lt;/p&gt;
&lt;p&gt;So I started from scratch and made up this GUI using minimal HTML markup, simple CSS (I use the &lt;a href=&quot;http://www.blueprintcss.org/&quot;&gt;blueprint&lt;/a&gt; CSS library as a foundation), the &lt;a href=&quot;http://jquery.com/&quot;&gt;jquery&lt;/a&gt; JavaScript library (including jQuery UI elements), and the &lt;a href=&quot;http://www.famfamfam.com/lab/icons/silk/&quot;&gt;famfamfam silk&lt;/a&gt; icon set.&lt;/p&gt;
&lt;p&gt;This is not &lt;strong&gt;TOTALLY&lt;/strong&gt; OSX themed, as I couldn’t find any tabs anywhere in OSX that worked for web apps (at least not easily implemented ones), so I used the jQuery tabs instead and just made them match as close as possible to the rest of the theme.&lt;/p&gt;
&lt;h4 id=&quot;caveat&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/osx-styled-web-gui/#caveat&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Caveat&lt;/h4&gt;
&lt;p&gt;This will not work in IE (I’m pretty sure, but haven’t tested), but it does work in modern versions of WebKit-based browsers (Safari and Chrome) and Firefox.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/jonmagic/webapp_gui/tree/master&quot;&gt;Here is the link to my GitHub repo&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>What is my passion?</title>
    <link href="https://jonmagic.com/posts/what-is-my-passion/"/>
    <updated>2008-08-21T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/what-is-my-passion/</id>
    <content type="html">&lt;p&gt;I’ve had a hard time with this question lately, and it has been coming up time and time again. I’ve been praying about, asking for guidance, trying to figure out what I should be pouring my heart into.&lt;/p&gt;
&lt;p&gt;While nothing really jumps out, here are a few things that I enjoy doing and do a lot:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;My job, fixing people’s computers, making people happy&lt;/li&gt;
&lt;li&gt;My family, doing all the little things that make Natalie happy, even if she doesn’t realize it&lt;/li&gt;
&lt;li&gt;Programming, for fun, for work, for side projects&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So according to &lt;a href=&quot;http://www.43folders.com/2008/08/19/good-blogs&quot;&gt;this article&lt;/a&gt;, I should blog about something I’m passionate about. I guess I’ll have to redefine that to &lt;em&gt;somethings&lt;/em&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Summer in a nutshell</title>
    <link href="https://jonmagic.com/posts/summer-in-a-nutshell/"/>
    <updated>2008-08-21T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/summer-in-a-nutshell/</id>
    <content type="html">&lt;p&gt;Last year I got married. Natalie and I had bought a house in Elkhart, Indiana, and we moved there the same week we married and have been making a home here since then. My memory is so bad I can’t remember what we did last fall, winter, or spring, but I do remember most of this summer 😃&lt;/p&gt;
&lt;p&gt;Natalie started a new job this summer and is loving it. Late spring I picked up a bad habit, gaming, and it has stuck with me through the summer. More notable is our vacation in June, where my brother-in-law and sister-in-law came up to stay with us, and we rocked Elkhart AND Chicago 😃&lt;/p&gt;
&lt;p&gt;But the most important thing that happened this summer in our lives wasn’t even something that happened directly to us. My parents finally got all their support (to become missionaries), spent a couple months getting ready, and flew to Argentina to start new lives as church planters (these events did not necessarily happen in that order). This has affected us though—now neither Natalie nor I have parents close by. The closest immediate relative is my sister, an hour away.&lt;/p&gt;
&lt;p&gt;As summer closes up we reflect. It was a good summer, full of life changes, some surprises, many blessings, and a few hard times.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Getting hacked</title>
    <link href="https://jonmagic.com/posts/getting-hacked/"/>
    <updated>2008-06-20T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/getting-hacked/</id>
    <content type="html">&lt;p&gt;My worst nightmare happened last night, and I didn’t even know it until late this morning. I was hacked…&lt;/p&gt;
&lt;h3 id=&quot;sequence-of-events%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/getting-hacked/#sequence-of-events%3A&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Sequence of events:&lt;/h3&gt;
&lt;h4 id=&quot;june-19th&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/getting-hacked/#june-19th&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; June 19th&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;10pm EST – hacker figured out my email password, logged in, and sent out a mass email to the top 20 people on my contact list (most contacted people), thankfully gmail calculates this list only when you use the web interface in gmail, which I haven’t used in quite some time since I switched to using Apple Mail.app. Most everyone on the top 20 were family or friends. Mysteriously the hacker does not send the mass mail to Sam or Xian, who were both on my top 20 list. The two people who would have known to call me (rather than email me) and tell me to take immediate action.&lt;/li&gt;
&lt;li&gt;10:16pm EST – Hacker? tries logging into my blog admin section from this ip 90.194.192.57 unsuccessfully&lt;/li&gt;
&lt;li&gt;10:20pm EST – Hacker? successfully logs into my blog admin section from this ip 88.191.47.11&lt;/li&gt;
&lt;li&gt;10:23pm EST – Magically whoever logged in at 10:20 is now logged in under a different ip 128.197.11.30 and figuring out my blogging system&lt;/li&gt;
&lt;li&gt;10:29pm EST – Hacker figures out my layout management system and starts adding javascript to my template files, first my tag.liquid file&lt;/li&gt;
&lt;li&gt;10:31pm EST – Hacker finds my layout.liquid file, the master layout, and adds several javascript lines in there. They cause anyone who visits my site to get forwarded to a nasty porn storm site, and installed some sort of tracking js linked to &lt;a href=&quot;http://cetrk.com/&quot;&gt;cetrk.com&lt;/a&gt; and crazyegg? Keeps updating the&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>i&#39;m stoked by the waybackmachine</title>
    <link href="https://jonmagic.com/posts/im-stoked-by-the-waybackmachine/"/>
    <updated>2008-05-29T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/im-stoked-by-the-waybackmachine/</id>
    <content type="html">&lt;p&gt;Man, I was just thinking the other day about all the content I’ve lost over the years switching blogging platforms. Then I listened to a podcast (most likely from Leo Laporte’s &lt;a href=&quot;http://twit.tv/&quot;&gt;TWIT&lt;/a&gt; network) and found out about the &lt;a href=&quot;http://archive.org/&quot;&gt;WayBackMachine&lt;/a&gt; on &lt;a href=&quot;http://archive.org/&quot;&gt;archive.org&lt;/a&gt;… I know I’ve heard of it before but always thought “what is that good for anyway???”&lt;/p&gt;
&lt;p&gt;Well today I checked it out, and all &lt;a href=&quot;http://web.archive.org/web/*/http://jonmagic.com&quot;&gt;my blog posts from 2004 and 2005&lt;/a&gt; are on there 😃
There are tons of other sites I’ve lost, most of which I probably won’t ever find not because the way back machine doesn’t have them, but because I can’t remember the URLs…&lt;/p&gt;
&lt;p&gt;Anyways, it was just fun reading some of the stuff I wrote a few years ago. I actually sounded smarter back then 😛&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Summer Project</title>
    <link href="https://jonmagic.com/posts/summer-project/"/>
    <updated>2008-04-21T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/summer-project/</id>
    <content type="html">&lt;p&gt;I’ve been using laptops for almost 7 years now, which means I haven’t really had the need for a desk in the last 7 years (I travel a lot for my job). I’ve been building my gaming rig over the last 2 months (since I’ve only started gaming again in the last few months) and it’s been living on an old dining room table in one of our bedrooms upstairs. While functional, it’s kinda wobbly and just doesn’t have the look and feel I want.&lt;/p&gt;
&lt;p&gt;So today I started building a desk from scratch (well, from wood actually). It’s gonna be a nice corner desk with one side dedicated to my gaming rig and the other side for my laptop and work related stuff (i.e. printer etc)…&lt;/p&gt;
&lt;p&gt;I’ll post photos of my current setup and then my new desk as building progresses. All I’ve started today is the tower cabinet that will hold the gaming rig; basic construction is done and trim has been cut but not attached.&lt;/p&gt;
&lt;p&gt;You can see the whole set of pictures on my &lt;a href=&quot;http://flickr.com/photos/jonmagic&quot;&gt;flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>New parts coming</title>
    <link href="https://jonmagic.com/posts/new-parts-coming/"/>
    <updated>2008-04-19T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/new-parts-coming/</id>
    <content type="html">&lt;p&gt;Ok, I broke down and purchased the next couple of upgrades for my gaming PC… The first is actually one I linked to on the last gaming pc rig post, the &lt;strong&gt;PNY Geforce 9600 GT with 512mb&lt;/strong&gt;… The second is this &lt;a href=&quot;http://tinyurl.com/2n767u&quot;&gt;little puppy&lt;/a&gt;, so I don’t run out of juice 😃 I’ll post how things work once my parts arrive!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>I&#39;m back! into games that is</title>
    <link href="https://jonmagic.com/posts/im-back-into-games-that-is/"/>
    <updated>2008-03-11T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/im-back-into-games-that-is/</id>
    <content type="html">&lt;p&gt;Ok, so that’s not quite true, I did play some Counter-Strike and stuff last year, but last night and today I really got back into gaming.&lt;/p&gt;
&lt;p&gt;What better way to get back into things than play &lt;a href=&quot;http://orange.half-life2.com/portal.html&quot;&gt;Portal&lt;/a&gt; by Valve… Part of the &lt;a href=&quot;http://orange.half-life2.com/index.html&quot;&gt;Orange Box&lt;/a&gt; this game is a strategy game from a first person perspective, and it was fantastic… I don’t know if I’ve ever enjoyed a game that much. The story was simple but interesting, the narrator/boss was hilarious, and it had the best game ending I’ve ever seen (I kinda knew how good the ending was before I played it though cuz of Jonathan Coultan’s jump into fame).&lt;/p&gt;
&lt;p&gt;Anyways, I guess Wednesday Xian is going to get me into Team Fortress 2 which he plays a lot and speaks very highly of…&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>I&#39;m building a computer</title>
    <link href="https://jonmagic.com/posts/im-building-a-computer/"/>
    <updated>2008-03-07T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/im-building-a-computer/</id>
    <content type="html">&lt;p&gt;I know, I know, that’s not a big deal considering I’m part owner in a computer store. But it IS a big deal to me, cuz this computer is going to be my tech/gaming machine for my house. Here is the spec list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.newegg.com/product/product.aspx?item=N82E16813131025&quot;&gt;Asus P5W DH Deluxe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Intel Core 2 Duo 2.2GHz with 2MB of L2 cache&lt;/li&gt;
&lt;li&gt;2GB of DDR2 667MHz memory&lt;/li&gt;
&lt;li&gt;80GB 7200rpm HDD&lt;/li&gt;
&lt;li&gt;plain old black computer case&lt;/li&gt;
&lt;li&gt;Lite-On 16x DVD-burner&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MOST IMPORTANT&lt;/strong&gt;: &lt;a href=&quot;http://www.xpcgear.com/gig9600gt.html&quot;&gt;Nvidia 9600GT video card&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Acer 19[LCD monitor](&lt;a href=&quot;http://www.newegg.com/Product/Product.aspx?Item=N82E16824009091&quot;&gt;http://www.newegg.com/Product/Product.aspx?Item=N82E16824009091&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;best keyboard I can find lying around&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.bestbuy.com/site/olspage.jsp?skuId=7105919&amp;amp;st=logitech+gaming&amp;amp;lp=4&amp;amp;type=product&amp;amp;cp=1&amp;amp;id=1109233585993&quot;&gt;Logitech MX-518 gaming mouse&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ll also either be setting up some nice speakers, or get a nice little USB headset for talking in my games 😃 Fun fun…&lt;/p&gt;
&lt;p&gt;Did I mention I’m stoked?&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Macbook Air smells like</title>
    <link href="https://jonmagic.com/posts/macbook-air-smells-like/"/>
    <updated>2008-01-16T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/macbook-air-smells-like/</id>
    <content type="html">&lt;p&gt;Nah, I know, &lt;a href=&quot;http://www.apple.com/macbookair/&quot;&gt;it’s pretty&lt;/a&gt;. But has anyone else noticed that they are switching back to &lt;a href=&quot;http://forums.macrumors.com/showthread.php?p=4762051&quot;&gt;IDE&lt;/a&gt;? I thought that everything was going to SATA. I guess after reading up that it doesn’t make much difference, but, whatever.&lt;/p&gt;
&lt;p&gt;Ok, so I’m upset because I wanted a new laptop, and they didn’t come out with one I want. Guess I’ll have to wait for the MacBook Pro updates.&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Capistrano recipe and howto for Rails, Mongrel, and Nginx</title>
    <link href="https://jonmagic.com/posts/capistrano-recipe-and-howto-for-rails-mongrel-and-nginx/"/>
    <updated>2008-01-10T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/capistrano-recipe-and-howto-for-rails-mongrel-and-nginx/</id>
    <content type="html">&lt;h3 id=&quot;update%3A-this-is-outdated-due-to-the-release-of-capistrano-2%E2%80%A6-i-will-work-on-a-new-tutorial-as-soon-as-i-have-a-project-i-need-to-deploy%E2%80%A6-1-10-08&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/capistrano-recipe-and-howto-for-rails-mongrel-and-nginx/#update%3A-this-is-outdated-due-to-the-release-of-capistrano-2%E2%80%A6-i-will-work-on-a-new-tutorial-as-soon-as-i-have-a-project-i-need-to-deploy%E2%80%A6-1-10-08&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; UPDATE: This is outdated due to the release of Capistrano 2… I will work on a new tutorial as soon as I have a project I need to deploy… 1-10-08&lt;/h3&gt;
&lt;p&gt;All righty then. Recently my firm (&lt;a href=&quot;https://web.archive.org/web/2012/http://www.sabretechllc.com&quot;&gt;SabreTech&lt;/a&gt;) got a contract to write and deploy a fairly complicated web app for a local business. Immediately I asked my friend &lt;a href=&quot;http://mintchaos.com/&quot;&gt;Xian&lt;/a&gt; to give me some deployment ideas, and he suggested I use &lt;a href=&quot;http://nginx.net/&quot;&gt;nginx&lt;/a&gt; as my web server instead of &lt;a href=&quot;http://www.apache.org/&quot;&gt;Apache&lt;/a&gt; as well as &lt;a href=&quot;http://slicehost.com/&quot;&gt;Slicehost&lt;/a&gt; as my vps host provider…&lt;/p&gt;
&lt;p&gt;So I set up my Slicehost account and started hacking. About a week later (five hours of work snuck in here and there), I’ve got my vps up and running smoothly. I’ve been using &lt;a href=&quot;http://weblog.jamisbuck.org/2006/3/6/switchtower-renamed&quot;&gt;Capistrano&lt;/a&gt; for deployment for awhile, but I also wanted to use it to set up my server, and that is when I ran across deprec. &lt;a href=&quot;http://deprec.rubyforge.org/&quot;&gt;Deprec&lt;/a&gt; is a nice little gem with a ton of capistrano recipes for setting up and deploying a server. It had some great recipes for deploying to &lt;a href=&quot;http://ubuntu.org/&quot;&gt;Ubuntu&lt;/a&gt;, so I chose Ubuntu as my OS for my new slice (vps).&lt;/p&gt;
&lt;p&gt;Now I just had to write some of my own recipes for setting up and deploying with Nginx instead of Apache. That is where most of my time was spent. Below you’ll find my instructions and recipes:&lt;/p&gt;
&lt;h4 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/capistrano-recipe-and-howto-for-rails-mongrel-and-nginx/#prerequisites&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Prerequisites&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Install the capistrano and deprec gems on your development machine&lt;/li&gt;
&lt;li&gt;Cap your app; in the root of your app dir, run: &lt;code&gt;cap -A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set up deprec: from the root of your app, run &lt;code&gt;deprec_dotfiles&lt;/code&gt; which just creates a file in your user dir called &lt;code&gt;.caprc&lt;/code&gt;, which contains the following line:
&lt;code&gt;require &#39;deprec/recipes&#39;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Your server must be running ubuntu (it should work on any debian based OS though)&lt;/li&gt;
&lt;li&gt;Your svn repository must be accessible by the same user listed in your &lt;code&gt;deploy.rb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://jonmagic.com/assets/2008/1/10/nginx.conf.txt&quot;&gt;&lt;code&gt;nginx.conf&lt;/code&gt;&lt;/a&gt;, &lt;code&gt;database.yml.production&lt;/code&gt;, and &lt;code&gt;deploy.rb&lt;/code&gt; must exist and be configured in &lt;code&gt;app/config&lt;/code&gt; (and checked into your repository)&lt;/li&gt;
&lt;li&gt;You need to take &lt;a href=&quot;http://jonmagic.com/assets/2008/1/10/jonmagic_recipes.txt&quot;&gt;this file&lt;/a&gt; and append the contents to the bottom of your &lt;code&gt;config/deploy.rb&lt;/code&gt; (these are the recipes I wrote)&lt;/li&gt;
&lt;li&gt;Make sure and configure the mongrel settings in your &lt;code&gt;deploy.rb&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;instructions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/capistrano-recipe-and-howto-for-rails-mongrel-and-nginx/#instructions&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Instructions&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Log into your server as root and add a new user (the user you specify in your &lt;code&gt;deploy.rb&lt;/code&gt;), set the password, and finally add to sudoers file
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;useradd -m bobby&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;passwd bobby&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visudo&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;From the root of your app run:
&lt;code&gt;cap install_rails_stack_with_nginx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The last one takes a while, but when it is done run:
&lt;code&gt;cap svn_cache_credentials&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Finally run:
&lt;code&gt;cap deploy_first_time&lt;/code&gt;
&lt;ol&gt;
&lt;li&gt;(When it asks for mysql user password just press enter, unless you changed the mysql root password)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;files&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/capistrano-recipe-and-howto-for-rails-mongrel-and-nginx/#files&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Files&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://jonmagic.com/assets/2008/1/10/nginx.conf.txt&quot;&gt;nginx.conf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://jonmagic.com/assets/2008/1/10/jonmagic_recipes.txt&quot;&gt;my recipes, add to bottom of deploy.rb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Gravy of life</title>
    <link href="https://jonmagic.com/posts/gravy-of-life/"/>
    <updated>2007-11-28T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/gravy-of-life/</id>
    <content type="html">&lt;p&gt;A &lt;a href=&quot;http://kimfromthesouth.blogspot.com/2007/11/mechanics-of-mashed-potatoes.html&quot;&gt;must read&lt;/a&gt; on my mom’s blog. Who knew she could take 15min of thanksgiving table fun and turn it into something worth reading 😃&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>SabreTech Employee blogs</title>
    <link href="https://jonmagic.com/posts/sabretech-employee-blogs/"/>
    <updated>2007-11-16T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/sabretech-employee-blogs/</id>
    <content type="html">&lt;p&gt;My team at SabreTech has been busy building their own personal blogs!&lt;/p&gt;
&lt;p&gt;Sam Sallows has his new blog up at
&lt;a href=&quot;http://www.samtheslacker.com/&quot;&gt;www.samtheslacker.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and Dan Parker has had his up for awhile at
&lt;a href=&quot;http://blog.behindlogic.com/&quot;&gt;blog.behindlogic.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sam already has an excellent bit on what we can do for clients that need to run older Windows apps that will only run on an old OS like Windows 2000 or Windows 98…&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Ultimate media/backup server</title>
    <link href="https://jonmagic.com/posts/ultimate-mediabackup-server/"/>
    <updated>2007-10-22T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/ultimate-mediabackup-server/</id>
    <content type="html">&lt;p&gt;I’ve been using a winxp box in my living room for some time now, and while it works really well, I do find it lacking. Currently it has a 200gb hdd and a 80gb hdd, runs xp pro, has a video card with composite out so I can go straight to the tv, has &lt;a href=&quot;http://azureus.sourceforge.net/&quot;&gt;Azureus&lt;/a&gt; and &lt;a href=&quot;http://www.rulecam.net/ted/&quot;&gt;ted&lt;/a&gt; to get tv shows,
&lt;a href=&quot;http://filehippo.com/download_klite_codec_pack/&quot;&gt;k-lite codec pack&lt;/a&gt; with Media Player Classic, and vnc so I can remote control it… Its pretty slick over all, but I’m running out of storage and I want something with more features.&lt;/p&gt;
&lt;h4 id=&quot;so-here-are-my-new-requirements%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/ultimate-mediabackup-server/#so-here-are-my-new-requirements%3A&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; So here are my new requirements:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Easily expandable storage, without reinstalling my OS or adding RAID cards etc…&lt;/li&gt;
&lt;li&gt;Smaller form factor, my current machine is a full desktop tower&lt;/li&gt;
&lt;li&gt;IR remote control and VNC&lt;/li&gt;
&lt;li&gt;auto download shows&lt;/li&gt;
&lt;li&gt;act as a backup resource for all my computers in the house, which means it has to have redundant storage&lt;/li&gt;
&lt;li&gt;looks pretty, both hardware and software&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Well, the only way I know how to meet those requirements is with a &lt;a href=&quot;http://www.apple.com/macmini/&quot;&gt;Mac Mini&lt;/a&gt; and a &lt;a href=&quot;http://www.drobo.com/&quot;&gt;Drobo&lt;/a&gt; storage device.&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;how-i%E2%80%99ll-pimp-the-mac-mini&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/ultimate-mediabackup-server/#how-i%E2%80%99ll-pimp-the-mac-mini&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; How I’ll pimp the Mac Mini&lt;/h4&gt;
&lt;p&gt;I’ll need at least a gig of RAM in the mini, doesn’t matter how big its HDD is though since the Drobo will be plugged into it. I’ll run Leopard with &lt;a href=&quot;http://azureus.sourceforge.net/&quot;&gt;Azureus&lt;/a&gt; and &lt;a href=&quot;http://www.rulecam.net/ted/&quot;&gt;ted&lt;/a&gt; to get my TV content. I’ll set up AFP and SMB file sharing on it so I can access this baby over the network. I’m not sure yet how I’ll remote control, might use VNC, might not???&lt;/p&gt;
&lt;h4 id=&quot;what-i%E2%80%99ll-do-with-the-drobo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/ultimate-mediabackup-server/#what-i%E2%80%99ll-do-with-the-drobo&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; What I’ll do with the Drobo&lt;/h4&gt;
&lt;p&gt;The drobo will be attached to the mini via USB 2.0. I’ll probably start with a few 250gb or 500gb drives, doesn’t matter cuz of the drobo’s magic!!! With the advent of Leopard and Time Machine I’ll be able to set this as a backup drive over the network for all my Macs, never having to worry about data loss again! I’m so excited about this part of it.&lt;/p&gt;
&lt;p&gt;Anyways, there are more details to figure out, and of course I need to find funding 😉 But one can always wish can’t they…&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Setting up a Mac</title>
    <link href="https://jonmagic.com/posts/setting-up-a-mac/"/>
    <updated>2007-08-15T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/setting-up-a-mac/</id>
    <content type="html">&lt;p&gt;Ok, I’ve setup quite a few Macs for friends and clients, tweaking things (even starting with a fresh install and only installing the necessary components, without any extra bloat), installing useful utilities, and arranging things to maximize workflow. I unfortunately have not recorded this process to date and a good friend of mine needs to reinstall his OS and set everything up due to a hard drive crash, so I guess now is finally the time to write down all the steps…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt;
When installing OS X make sure to click on any buttons that say “options” or “customize.” The first install screen that gives you one of these will ask if you want to install over top, or wipe and reinstall. I usually use the wipe option. The second screen that gives you one of these two buttons, if you click it, will let you remove all the extra programs you don’t need. I start by unchecking the box on printer drivers, unchecking fonts, unchecking languages, and then I pick through the extras, usually removing stuff like GarageBand, etc. Once you’ve got things tweaked, start the install (you can also skip the media check that it runs)…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt;
Some techies say you should create an admin account and then a locked down user account to run in on a daily basis. I find this a nuisance, so I just create my one user on the initial install, make sure I assign a password, and that’s that. If you have security concerns, go to your System Preferences, then to Accounts, click on Login Options, and tell it not to auto login that user.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt;
Run all your system updates: click on the Apple in the upper left, then click Software Update.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt;
Create a Downloads folder in your home directory or on your desktop, then open Safari and go to the Safari Preferences and set the default download location to that folder. Otherwise downloads go to your desktop and clutter things up real quick. This is a personal preference of course, so do what you will. Also, remove unnecessary icons on your dock and drag a shortcut to your home folder onto the dock (next to your garbage can &lt;strong&gt;NOT ON IT&lt;/strong&gt;!) and also drag your Applications folder onto your dock, next to the home folder shortcut you just put there 😃 On Macs shortcuts are technically called Aliases, but whateva…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt;
Tweak Safari a little more by going to Safari Preferences and unchecking the “Open Safe Files after downloading.” Also, I think in older versions of Safari you had to enable Tabbed browsing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 6:&lt;/strong&gt;
Disable Spotlight hot keys by clicking the Apple in the upper left, then click on System Preferences, then go to Spotlight, and on the first tab uncheck both the boxes at the bottom. You will need to do this so you can map &lt;code&gt;CMD-Space&lt;/code&gt; as Quicksilver’s hot key later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 7:&lt;/strong&gt;
Download your useful utilities and programs… Fire up Safari and start with these great programs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://quicksilver.blacktree.net/&quot;&gt;Quicksilver&lt;/a&gt; is an amazing file launcher/object manipulation tool. Super duper easy.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.mozilla.com/&quot;&gt;Firefox&lt;/a&gt; is an alternate web browser that many people like.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.caminobrowser.org/&quot;&gt;Camino&lt;/a&gt; is my preferred web browser for business type stuff.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.titanium.free.fr/pgs/english.html&quot;&gt;OnyX&lt;/a&gt; is a great program for tweaking stuff in OS X, including dock position, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.adiumx.com/&quot;&gt;Adium&lt;/a&gt; is an excellent multi-protocol chat program; it really covers all the bases.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.skype.com/&quot;&gt;Skype&lt;/a&gt; is great for voice and video chat; I use this with my fam and friends.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://joost.com/&quot;&gt;Joost&lt;/a&gt; is still invite-only, but you can sign up to get on the beta list. Joost is an online television set type thingy.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.newsgator.com/download/products/NetNewsWireLite2.1.1.dmg.zip&quot;&gt;NetNewsWire Lite&lt;/a&gt; is an excellent news reader application! Make sure and subscribe to &lt;a href=&quot;http://jonmagic.com/feed/atom.xml&quot;&gt;my feed&lt;/a&gt; once you install it 😃&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was thinking I used a lot more programs, but with web-based applications really starting to be just as functional as desktop apps, I don’t use nearly as many desktop apps as I used to. Here are some web apps I use all the time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://gmail.com/&quot;&gt;Gmail&lt;/a&gt; is a free email solution, by far the best in my opinion.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.google.com/&quot;&gt;Google Docs and Spreadsheets&lt;/a&gt; has completely replaced Microsoft Office for my needs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://calendar.google.com/&quot;&gt;Google Calendar&lt;/a&gt; is a flexible calendar with great sharing capabilities. I also use &lt;a href=&quot;http://chip.cuccio.us/projects/gcal/&quot;&gt;Gcal&lt;/a&gt; as a standalone desktop interface to Gcal.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://del.icio.us/&quot;&gt;Del.icio.us&lt;/a&gt; handles all my bookmarks. I make sure and go to their help section and drag both the “post to &lt;a href=&quot;http://del.icio.us/&quot;&gt;del.icio.us&lt;/a&gt;” and “my &lt;a href=&quot;http://del.icio.us/&quot;&gt;del.icio.us&lt;/a&gt;” bookmarklets onto my bookmarks bar in all my browsers. In Safari, if you make them the first two bookmarks on your bookmarks bar, you can access them with &lt;code&gt;CMD-1&lt;/code&gt; and &lt;code&gt;CMD-2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://flickr.com/&quot;&gt;Flickr&lt;/a&gt; is where I store all my digital photos online. I guess I mostly just use iPhoto on my laptop though, and then upload to Flickr for backup.&lt;/li&gt;
&lt;li&gt;I have reluctantly started using &lt;a href=&quot;http://www.facebook.com/&quot;&gt;Facebook&lt;/a&gt; to keep in contact with people, and their Pictures section is also really handy for getting photos to friends and family.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Step 8:&lt;/strong&gt;
Go to the folder you downloaded all these great programs to and start double clicking those installer icons 😃 Some you will expand to a new folder, and then you can drag the app over to your Applications folder on your dock (if you followed step 4). Other installers will actually run a full fledged install app that will copy things to the appropriate places automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 9:&lt;/strong&gt;
Go to your Applications folder and look for Quicksilver, which you copied there in the previous step… Double click it and follow the setup instructions. I always re-assign my hotkey to &lt;code&gt;CMD-Space&lt;/code&gt; for ease of use. Once Quicksilver is loaded, press &lt;code&gt;CMD-Space&lt;/code&gt; to open it, then press &lt;code&gt;CMD-,&lt;/code&gt; to open Quicksilver Preferences. I set mine to start at login and sometimes tweak some other settings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 10:&lt;/strong&gt;
I like to open up OnyX and set my dock to the right-hand side and so that it aligns to the bottom; that’s just me though.&lt;/p&gt;
&lt;p&gt;This is a good start. I’ll add to it as I think of more things 😃&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>It&#39;s about time</title>
    <link href="https://jonmagic.com/posts/its-about-time/"/>
    <updated>2007-08-02T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/its-about-time/</id>
    <content type="html">&lt;p&gt;I’m married!!!&lt;/p&gt;
&lt;p&gt;Had a beautiful wedding on the beach, &lt;a href=&quot;http://flickr.com/photos/mjmetts/987667290/&quot;&gt;check out how gorgeous Natalie was in her dress…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It was a wonderful wedding, about 20 of us on the beach…&lt;/p&gt;
&lt;p&gt;More pictures to follow 😃&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>sabretechllc.com redesigned!</title>
    <link href="https://jonmagic.com/posts/sabretechllccom-redesigned/"/>
    <updated>2007-07-13T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/sabretechllccom-redesigned/</id>
    <content type="html">&lt;p&gt;Wow, in preparation for our open house this weekend we have been on a mad spree: remodeling the office, making line cards, new business cards, gift certificates, new tables and chairs, &lt;strong&gt;AND&lt;/strong&gt; a &lt;a href=&quot;https://web.archive.org/web/2012/https://web.archive.org/web/2012/http://sabretechllc.com&quot;&gt;NEW WEBSiTE&lt;/a&gt;!!!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://mintchaos.com/&quot;&gt;Christian Metts&lt;/a&gt; took some ideas I had and a bunch of good ideas he had and threw together a layout with images in Photoshop in just a few hours. He sent me 4 images: a header, navbar background, navbar divider, a couple hex codes, and an image with the overall look and feel he wanted…&lt;/p&gt;
&lt;p&gt;I took everything he sent and threw it together into a fairly comparable real page using HTML, CSS, and images, all on top of &lt;a href=&quot;http://mephistoblog.com/&quot;&gt;mephisto&lt;/a&gt;. It took me about 4 hours, and then another 30 min of Christian showing me how to tweak stuff, and I have a gorgeous site that works in 6 browsers (that’s how many I’ve tested so far). Check out the &lt;a href=&quot;http://jonmagic.com/assets/2007/7/13/before.png&quot;&gt;before&lt;/a&gt;, &lt;a href=&quot;http://jonmagic.com/assets/2007/7/13/mockup.png&quot;&gt;mockup&lt;/a&gt;, and &lt;a href=&quot;https://web.archive.org/web/2012/https://web.archive.org/web/2012/http://sabretechllc.com&quot;&gt;after&lt;/a&gt; pictures…&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>By the grace of God</title>
    <link href="https://jonmagic.com/posts/by-the-grace-of-god/"/>
    <updated>2007-06-06T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/by-the-grace-of-god/</id>
    <content type="html">&lt;p&gt;I’m getting married August 2nd on a beach in Florida…&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>ATT is not my friend</title>
    <link href="https://jonmagic.com/posts/att-is-not-my-friend/"/>
    <updated>2007-03-28T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/att-is-not-my-friend/</id>
    <content type="html">&lt;p&gt;When we bought SabreTech, Brad and I had our phone service changed and found out a nice little policy of ATT (SBC at the time)… We were paying for a static IP address, which means our internet address won’t change on a day to day, year to year basis… But it turns out, if you make any kind of change to your account, dsl or regular phone stuff, they assign you a new set of IPs… This is a major pain for a company like ours, so we’ve avoided making changes to our account since then.&lt;/p&gt;
&lt;p&gt;Until last month that is, when we had to have some of our phone stuff fixed because ATT screwed it up (won’t go into details)… Anyways, when we called to have this stuff fixed, we were assured our IPs wouldn’t change…&lt;/p&gt;
&lt;p&gt;Welcome Today, guess what I find when I get into work this morning… Our internet is down, and I have a sneaking suspicion it is because they changed our IPs… I call ATT dsl tech support, and after they tested the line I suggested they check what IP range I was assigned and sure enough, they changed it… I was irate, and for once that produced results (I never know which way to go with these things, play the nice guy, or play the frustrated client)…&lt;/p&gt;
&lt;p&gt;Thankfully, unlike last time, they were able to get us back up and running within 30 minutes (I had to stay on hold the entire time). This whole thing just burns me though, I’m tired of working with large corps that can’t tell their head from their tail, and unfortunately there are no other options around here… So I guess you just have to pay the price, and lose several hours of your life a year for stupid stuff like this… So if anyone ever tells you service x only costs y dollars from large corp z, make sure you figure in the time you’ll have dealing with their stupidity…&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Wedding postponed</title>
    <link href="https://jonmagic.com/posts/wedding-postponed/"/>
    <updated>2007-03-22T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/wedding-postponed/</id>
    <content type="html">&lt;p&gt;Our wedding has been postponed temporarily, I will let everyone know as soon as we have a new date.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>I&#39;m officially Jon Magic</title>
    <link href="https://jonmagic.com/posts/im-officially-jon-magic/"/>
    <updated>2007-03-09T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/im-officially-jon-magic/</id>
    <content type="html">&lt;p&gt;I know I know, I market the heck out of JonMagic, but today it’s official… I got my first credit card in the mail with the name Jon Magic on it 😃&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Computers shutting down everywhere</title>
    <link href="https://jonmagic.com/posts/computers-shutting-down-everywhere/"/>
    <updated>2007-03-08T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/computers-shutting-down-everywhere/</id>
    <content type="html">&lt;p&gt;I’ve got 6 computers, in 2 states, across 4 clients, all shutting down or restarting randomly… This started happening about 3 weeks ago. There are no similarities between these machines—some I built, some are from other local computer places. None of them have the same motherboard or processor… The only thing linking them is they are all running Windows XP.&lt;/p&gt;
&lt;p&gt;I guess this is a cry for help—anyone experiencing the same thing?&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>I&#39;m ready to teach... well, almost</title>
    <link href="https://jonmagic.com/posts/im-ready-to-teach-well-almost/"/>
    <updated>2007-01-20T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/im-ready-to-teach-well-almost/</id>
    <content type="html">&lt;p&gt;Two years ago while on vacation in Florida I had an epiphany, one of those moments where something just comes to you, and it feels so right.&lt;/p&gt;
&lt;p&gt;My epiphany was to take my consulting business and turn it into a chain, eventually a nationwide chain. There were several pieces to this dream, the first being starting some sort of school to train techs/tech managers, the second being giving them a financial platform to go out and start their own businesses under a larger nationwide corporate entity.&lt;/p&gt;
&lt;p&gt;Thankfully I didn’t jump with this idea. The infamous GeekSquad started taking off about that time and we now see what a failed experiment that has been. But today my brain juices are flowing again and I’m getting that bug to do something bigger, bigger than what I’m doing right now.&lt;/p&gt;
&lt;p&gt;Now don’t get me wrong, I have absolutely nothing to complain about with my current situation. In those two years since my epiphany I’ve partnered with Brad Cochran and bought a computer sales/service business (SabreTech), and then taken that business from a large debt to out of debt in 18 months (we were blessed to do it so quickly), and 2007 promises to be an absolutely amazing year.&lt;/p&gt;
&lt;p&gt;Ok, so I was talking about them there brain juices. Learning from GeekSquad’s failure, I’m not so interested in doing the nationwide sales/service chain thing, but I am interested in the first part of my original epiphany, the tech/business school idea. I think this is an open wide market right now, and I don’t know of any school that is doing it right. There are the ITT tech schools, the 4 year schools with BS’s in computer science, and of course online tech schools. You can also just skip school and go take classes to get IT certifications, specializing in hardware/software/Microsoft/Linux/Web, just to name a few. But how valuable are these really? The people in the tech industry that I respect, that are really going somewhere, don’t seem to be recommending these sorts of education to anyone. So what does it take to become an IT industry leader, a professional with the skills needed to be a great, not good, but great IT consultant (I’m focusing on consultants because I’ve always had a place in my heart for small to medium businesses that can’t afford a dedicated IT person, so they outsource)…&lt;/p&gt;
&lt;p&gt;This list will be updated as I continue this thought, but here is a start:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Willing and eager to learn&lt;/li&gt;
&lt;li&gt;Able to be self taught&lt;/li&gt;
&lt;li&gt;Daring, but cautious at the same time&lt;/li&gt;
&lt;li&gt;Calm, cool, and collected&lt;/li&gt;
&lt;li&gt;Efficient&lt;/li&gt;
&lt;li&gt;Good with people&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; Can these qualities be taught?&lt;/p&gt;
&lt;p&gt;None of these things are specific to IT, in fact, a good tech doesn’t have to have tons of experience with computers if they have these skills. I’m not pulling these ideas out of the air. To be honest, from my personal experience, when I walk into a client’s business and am presented with the problem, over half the time I haven’t encountered the problem, and therefore do not know the solution.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Buffalo Technology, please redeem yourself</title>
    <link href="https://jonmagic.com/posts/buffalo-technology-please-redeem-yourself/"/>
    <updated>2007-01-19T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/buffalo-technology-please-redeem-yourself/</id>
    <content type="html">&lt;p&gt;I’ve been eyeing the &lt;a href=&quot;http://www.buffalo-technology.com/products/product-detail.php?productid=97&quot;&gt;Buffalo Terastation&lt;/a&gt; for awhile now, lots of storage in a nice little package. So when the opportunity to buy one came up, I jumped.&lt;/p&gt;
&lt;p&gt;One of my clients needed a file storage / backup solution, and the Terastation seemed to fit the bill. I found it for a great price (1TB for 6 bills), punched in my credit card number, and 4 days later it was in my hands.&lt;/p&gt;
&lt;p&gt;I received the unit the middle of December, but we were so busy at &lt;a href=&quot;https://web.archive.org/web/2012/http://www.sabretechllc.com&quot;&gt;SabreTech&lt;/a&gt; I scheduled the install for after the first of the year. I did go ahead and set the unit up, configured everything via the web interface, and tested it. I left in on the bench for 24 hours running, and then logged in and shut it down, everything seemed to be perfect.&lt;/p&gt;
&lt;p&gt;Fast forward 3 weeks, when I go onsite and begin the setup for the client. After plugging it in it did its Star Trek like flashy light thing, then signaled that drives 2, 3, and 4 were either full or not working. I logged into the web interface, and it said those drives were not attached. So I shut it down and then started it back up; same thing. Rinse and repeat, again, the same result… So I took it back to my office, started it up and called tech support.&lt;/p&gt;
&lt;p&gt;Fast forward 30 minutes, on hold, finally I get to talk to tech support. They decide the controller must be the problem, as the likelihood of three drives going bad at the same time was slim to none. So they put me on hold and then forwarded me to the RMA department. The RMA department took my info and said they would email me instructions to do an advanced RMA (they ship me a new unit, I ship the old one back in the same box the new one came in, and they provide the shipping tag).&lt;/p&gt;
&lt;p&gt;Two hours later I got the email and forwarded it to Brad. He had problems getting the link to work, so I went ahead visited the link (no problem on my computer), and printed the form we needed to fill out and fax in. Brad filled in the form later that day, and the next day I took it somewhere to fax it (we can’t fax long-distance from our office). I faxed it, the fax machine printed out the receipt when it was done, and I forgot about it… That was on Thursday the 11th of January.&lt;/p&gt;
&lt;p&gt;Fast forward to this Monday (the 15th) when Brad asked if I had heard anything from Buffalo on our RMA status. By this time we should have received either an email saying our new unit was on its way, or at least a confirmation that they had received our fax. I had nothing, so I called their tech support number again, waited on hold 45 minutes, finally got the tech, who forwarded to the RMA department, who proceeded to tell me they had not received my fax (great)… So I drove somewhere to use a fax machine, faxed it twice (just to be sure), and then called Buffalo again.&lt;/p&gt;
&lt;p&gt;By this time I’m not really happy that I have to wait on hold twice each time I call to talk to someone in the RMA department, so after waiting 30 minutes on hold to get a tech, and then another 15 minutes on hold to get someone in RMA, I’m getting a bit hot under the collar. I asked the RMA person whether they had received my fax, they looked and said no. They asked what fax number I sent it to and then told me that was the fax number for the accounting department. After a little bit they figured out that advance RMA requests go to accounting due to the credit card info that is needed, and then it is forwarded to the RMA department. So they had me fax everything to a different number and confirmed that they received it, said they would fast track it and I should get an email within a day or two.&lt;/p&gt;
&lt;p&gt;This morning I asked Brad if he had heard from Buffalo, and no was the answer. So this afternoon I called AGAIN, waited on hold for 30 minutes and finally got a tech, who once AGAIN forwarded me to to the RMA department. The girl was very nice as I explained all that had transpired, and took care to read everything they had on their computers, and basically told me they had no idea why it hadn’t shipped out (they did say something about their inter-departmental computer systems taking 24-48 hours to update, what is that about?). Then they promised someone would call me by the end of the business day to let me know where things were at.&lt;/p&gt;
&lt;p&gt;Well, the end of the business day has come and gone, and I will never buy Buffalo again, even if they fix this… I know I titled the article with some sense of hope, but by the time I finished writing this, I realized I just don’t have the time to work with companies like this.&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Rounding out the year</title>
    <link href="https://jonmagic.com/posts/rounding-out-the-year/"/>
    <updated>2006-11-13T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/rounding-out-the-year/</id>
    <content type="html">&lt;p&gt;What a great year! Here are some of the things I thank God for everyday:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I’m &lt;a href=&quot;http://jonmagic.com/2006/8/4/i-m-engaged&quot;&gt;getting married!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Brad Cochran and I bought &lt;a href=&quot;https://web.archive.org/web/2012/http://www.sabretechllc.com&quot;&gt;SabreTech Consulting LLC&lt;/a&gt; just over a year and a half ago, and it is just about paid off…&lt;/li&gt;
&lt;li&gt;Good health the last 6 months (with the exception of today), I even had my wisdom teeth removed (finally!)&lt;/li&gt;
&lt;li&gt;I’ve had the opportunity to travel, a lot&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://jonmagic.com/2006/5/16/i-bought-one&quot;&gt;New laptop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;New (used) car… 98 Malibu&lt;/li&gt;
&lt;li&gt;Healthy family! My sis is back from school now too, and that is always nice…&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I had other ones, but just can’t remember them all right now… I’m sick and need to take a nap so I can get better, so I’m going to lie down now…&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>clearcheckbook.com, a step in the right direction</title>
    <link href="https://jonmagic.com/posts/clearcheckbookcom-a-step-in-the-right-direction/"/>
    <updated>2006-10-24T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/clearcheckbookcom-a-step-in-the-right-direction/</id>
    <content type="html">&lt;p&gt;I started using &lt;a href=&quot;http://clearcheckbook.com/&quot;&gt;clearcheckbook.com&lt;/a&gt; about a month ago and have found it an excellent way to keep track of my spending and account balances. I’m still working on finding a web-based budgeting app, but in the meantime &lt;a href=&quot;http://clearcheckbook.com/&quot;&gt;clearcheckbook.com&lt;/a&gt; is serving me quite well. They keep adding excellent features too, most notably (and recently) the ability to access my account via IM, and my new favorite feature, payment reminders (which are highly configurable)…&lt;/p&gt;
&lt;p&gt;I’m hoping &lt;a href=&quot;http://pearbudget.com/&quot;&gt;pearbudget.com&lt;/a&gt; gets their act together soon and gives me a nice web20 app to do the budgeting part, but in the meantime I’ll settle with my pencil and paper (sorry, just not a big Excel fan)…&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>My Rig</title>
    <link href="https://jonmagic.com/posts/my-rig/"/>
    <updated>2006-10-04T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/my-rig/</id>
    <content type="html">&lt;p&gt;Not that anyone cares, but I thought I’d post my current computer setup, hardware and software…&lt;/p&gt;
&lt;h3 id=&quot;the-hardware&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-rig/#the-hardware&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; The Hardware&lt;/h3&gt;
&lt;p&gt;I’m the kinda guy that enjoys the bleeding edge (first Mac was an 867mhz PB), so five days after Apple released the new &lt;a href=&quot;http://www.apple.com/macbook/macbook.html&quot;&gt;Macbook&lt;/a&gt; I had my company order one for me. I got a stock &lt;a href=&quot;http://store.apple.com/1-800-MY-APPLE/WebObjects/AppleStore.woa/6344003/wo/pQ4GzSFdUzhy2yFxQOmq26OsQGg/2.?p=0&quot;&gt;black Macbook&lt;/a&gt; from Apple, and ordered 2GB of RAM and a 120GB SATA laptop drive from a third party retailer (can’t remember who)…&lt;/p&gt;
&lt;p&gt;The day after the Macbook arrived my memory and harddrive showed up and I installed them. Needless to say, I will never own a Mac with less than 2GB of RAM after experiencing the difference between 512MB and 2GB.&lt;/p&gt;
&lt;p&gt;This computer is fast, really really fast, and the 120GB of harddrive made it more than comfortable for having my entire music/photos/movies collection on my laptop, instead of just my desktop machine at home.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://www.apple.com/macbook/isight.html&quot;&gt;iSight&lt;/a&gt; camera is really nice too, although I haven’t really started using it for video conferencing yet.&lt;/p&gt;
&lt;p&gt;I love having the black Macbook, but I don’t have anything against the white ones, they are really slick too. The black one does tend to show any grease transferred from your hands, which could drive someone with &lt;strong&gt;OCD&lt;/strong&gt; nuts.&lt;/p&gt;
&lt;h3 id=&quot;software&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-rig/#software&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Software&lt;/h3&gt;
&lt;p&gt;Well first off, I’m running &lt;strong&gt;OS X 10.4.8&lt;/strong&gt; now.&lt;/p&gt;
&lt;p&gt;In addition I bought &lt;a href=&quot;http://www.parallels.com/&quot;&gt;Parallels&lt;/a&gt; and I’m running &lt;a href=&quot;http://www.microsoft.com/windowsxp/pro/default.mspx&quot;&gt;Windows XP Pro&lt;/a&gt; and &lt;a href=&quot;http://www.ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt;. I use &lt;a href=&quot;http://virtuedesktops.info/&quot;&gt;VirtueDesktops&lt;/a&gt; to keep everything clean and easily switch between my OS’s. It is really a thing of beauty and I love to show it off to my clients and of course other geeks (I had it all setup when I went to &lt;a href=&quot;http://railsconf.org/&quot;&gt;RailsConf&lt;/a&gt;, so that was fun, being that only a few people out of the 100+ people with Macbooks had the same setup).&lt;/p&gt;
&lt;p&gt;I use &lt;a href=&quot;http://www.apple.com/ilife/&quot;&gt;iTunes, iPhoto, iMovie, and iDVD&lt;/a&gt; quite regularly. I gave &lt;a href=&quot;http://www.apple.com/macosx/features/mail/&quot;&gt;Apple Mail&lt;/a&gt; a spin but ended up back with the &lt;a href=&quot;http://gmail.com/&quot;&gt;Gmail&lt;/a&gt; web interface as my preferred mail client.&lt;/p&gt;
&lt;p&gt;For coding I use &lt;a href=&quot;http://www.macromates.com/&quot;&gt;Textmate&lt;/a&gt; and &lt;strong&gt;IMHO&lt;/strong&gt; there is nothing better.&lt;/p&gt;
&lt;p&gt;In addition to these I use &lt;a href=&quot;http://chip.cuccio.us/projects/gcal&quot;&gt;Gcal&lt;/a&gt; (a webkit based Google Calendar client), &lt;a href=&quot;http://mozilla.com/&quot;&gt;Firefox 1.5.0.7&lt;/a&gt;, &lt;a href=&quot;http://www.apple.com/macosx/features/safari/&quot;&gt;Safari&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Stickies&quot;&gt;Stickies&lt;/a&gt;, &lt;a href=&quot;http://www.newsgator.com/NGOLProduct.aspx?ProdId=NetNewsWire&amp;amp;ProdView=lite&quot;&gt;NetNewsWire Lite&lt;/a&gt;, Terminal, and a handful of other apps.&lt;/p&gt;
&lt;h3 id=&quot;problems%2Fissues&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://jonmagic.com/posts/my-rig/#problems%2Fissues&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt; Problems/Issues&lt;/h3&gt;
&lt;p&gt;I’ll finish this post off by mentioning some of the hardware issues I’ve experienced with my Macbook.&lt;/p&gt;
&lt;p&gt;The first was an inconvenient problem with the gloriously large trackpad. Due to its large size, and the poor (I hate to say poor, but how else can I describe it?) trackpad button design, the button would only work if I clicked within an inch of the center. This after two weeks of use. I found a nice little remedy (via Google) &lt;a href=&quot;http://ibloggedthis.com/2006/06/29/an-origami-solution-to-the-apple-macbook-trackpad-squishy-button-problem/&quot;&gt;using some origami&lt;/a&gt;, and it hasn’t been an issue since.&lt;/p&gt;
&lt;p&gt;The last and worst issue I can remember is when I got the &lt;a href=&quot;http://forums.macrumors.com/showthread.php?t=213531&quot;&gt;random macbook shutdown problem&lt;/a&gt;. Four weeks after I started using my Macbook it started shutting down whenever it felt like. Fortunately it seemed to do it more at night and not during work hours. But after a few days it was doing it all the time. I called Apple and started going through their annoying diagnostics: installing the factory RAM, installing the factory harddrive, reinstalling the OS, etc etc. Finally I got an &lt;strong&gt;RMA&lt;/strong&gt; and sent it in. &lt;strong&gt;BUT&lt;/strong&gt;, it took 16 days for them to get it back to me, which was extremely annoying, especially after being assured it would be back in 7 days.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>web20 and economics?</title>
    <link href="https://jonmagic.com/posts/web20-and-economics/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/web20-and-economics/</id>
    <content type="html">&lt;p&gt;I’m bored… I’m working pretty hard at &lt;a href=&quot;https://web.archive.org/web/2012/http://www.sabretechllc.com&quot;&gt;Sabretech&lt;/a&gt;, trying to bring home the bacon, but it is just not enough…&lt;/p&gt;
&lt;p&gt;I’ve been spending every extra free time moment reading up on and studying this web trend called web 2.0… What is it about, you ask? Mr. O’Reilly &lt;a href=&quot;http://radar.oreilly.com/archives/2005/10/web_20_compact_definition.html&quot;&gt;gets it right&lt;/a&gt;, I think…&lt;/p&gt;
&lt;p&gt;So, I really want to contribute somehow, but I’m a nobody in the web 2.0 world, and honestly haven’t had many groundbreaking ideas in a long time (if ever)… But I will not be deterred, so I’ve decided to start thinking about web 2.0 from an economic standpoint, since that was my focus in college…&lt;/p&gt;
&lt;p&gt;That said, don’t come back here looking for amazing insights or anything. Maybe—just maybe—though, I’ll have an epiphany and “make it” in the web 2.0 movement 😃&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The longest weekend of my life</title>
    <link href="https://jonmagic.com/posts/the-longest-weekend-of-my-life/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/the-longest-weekend-of-my-life/</id>
    <content type="html">&lt;p&gt;I don’t even know where to begin… Simply put, an onsite I started on Friday morning turned into an all weekend marathon of Windows 2000 Small Business Server hacking, repeated reinstalls, Mountain Dew, energy drinks, 3 hours of sleep here, 2 there, running between 25 workstations configuring them and cleaning them up, and a whole lot more… It is now a little past 7pm on Sunday and I’m just praying that I can go home soon…&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Learning Rails</title>
    <link href="https://jonmagic.com/posts/learning-rails/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/learning-rails/</id>
    <content type="html">&lt;p&gt;Wow, what a couple of weeks (months) it has been…&lt;/p&gt;
&lt;p&gt;My intro to &lt;a href=&quot;http://www.rubyonrails.com/&quot;&gt;rails&lt;/a&gt; began a few months ago when a &lt;a href=&quot;http://mintchaos.com/&quot;&gt;good friend and webdev guy&lt;/a&gt; told me he was using it heavily and suggested I check it out… I have never had any real programming experience and while the &lt;a href=&quot;https://www.youtube.com/watch?v=Gzj723LkRJY&quot;&gt;rails intro video&lt;/a&gt; was cool I just couldn’t really get into it (scared, I think). SO, I stayed away for a little while, then came back and jumped on the bandwagon by adopting &lt;a href=&quot;https://github.com/ManuInNZ/typo&quot;&gt;Typo&lt;/a&gt;, a nice little blogging app with a lot of functionality, all built on &lt;a href=&quot;http://www.rubyonrails.com/&quot;&gt;rails&lt;/a&gt;… this saved me from having to learn how to program for a few more months and started to whet my appetite to learn more.&lt;/p&gt;
&lt;p&gt;Then, about 4 weeks ago someone (who shall remain nameless) looked me up and asked me to build a web app… I could have shoved the project off on Joshaven, but he is already crazy busy, so I decided to commit. No more hiding in the shadows, no more chickening out because I don’t know how to program, no more excuses… SO, I warned the client that I had no idea what I was doing and asked if he was still willing to pay me, and he was 😃 so now I’m knee deep in this stuff and it’s only getting deeper…&lt;/p&gt;
&lt;p&gt;After throwing together a pretty much non-functional demo, and convincing myself that I could do this, I decided I needed to read a book on programming in Ruby before I could really get comfortable in rails. So I ran on down to &lt;a href=&quot;https://poignant.guide/&quot;&gt;why’s poignant guide to ruby&lt;/a&gt; and finished it in a weekend. Since then life has been a lot easier, at least as far as programming goes.&lt;/p&gt;
&lt;p&gt;So I jumped back into the project, started from scratch, and built a highly functional, even pretty, demo in 20 hours (two days)… The client liked it and my friends and family even checked it out. That was Tuesday of last week.&lt;/p&gt;
&lt;p&gt;Today is Sunday, although by the time I post this it will be Monday. I spent 3 days trying to get RMagick installed on my computer, finally succeeding late last night. Since then I’ve revamped version 1 of the webapp to run faster, use better naming schemes, and have cleaner code all around (thanx for the input &lt;a href=&quot;http://mintchaos.com/&quot;&gt;xian&lt;/a&gt;, I took your advice on combining controllers).&lt;/p&gt;
&lt;p&gt;And that is my learning &lt;a href=&quot;http://www.rubyonrails.com/&quot;&gt;rails&lt;/a&gt; experience. Five slow months of avoiding the inevitable and then four crazy &lt;a href=&quot;http://www.rubyonrails.com/&quot;&gt;rubyonrails&lt;/a&gt; filled weeks.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>It&#39;s just the weather, thats all...</title>
    <link href="https://jonmagic.com/posts/its-just-the-weather-thats-all/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/its-just-the-weather-thats-all/</id>
    <content type="html">&lt;p&gt;Good morning…&lt;/p&gt;
&lt;p&gt;Isn’t this great weather we’ve been having! Temps have been in the 50’s and 60’s, thunderstorms have been rolling through… I love a good storm.&lt;/p&gt;
&lt;p&gt;So I’m wrapping up a big programming project, just doing the final touches here and there, addressing the customers final concerns, and I’ve already started my next project. Sabretech is in dire need of a trouble ticket system better than the one we’re using… We currently use the ticket system module in &lt;a href=&quot;http://www.egroupware.org/&quot;&gt;egroupware&lt;/a&gt;, as well as the egroupware calendar module. I can say we are less than thrilled with our current situation… So I’ve started this new project and called it Optiks, short for Opportunity Tickets. As you can see, the first thing we’re dropping is the Trouble part 😃 Dad suggested this, hehe… I’m designing and building this with &lt;a href=&quot;http://37signals.com/&quot;&gt;37 Signals&lt;/a&gt; methodology in mind… Some people would like it to have everything and the kitchen sink… I’m mostly just interested in it doing a few simple things really well, with a nice API and the ability to expand and change it later on… So that is what I’m doing!&lt;/p&gt;
&lt;p&gt;Also, looks like I’ll be jamming with Roll the Dice this coming Friday night… I played in church this morning, and then practiced this afternoon with RtD… We didn’t sound too bad i guess 😃&lt;/p&gt;
&lt;p&gt;Good Night…&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>I&#39;m Engaged!</title>
    <link href="https://jonmagic.com/posts/im-engaged/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/im-engaged/</id>
    <content type="html">&lt;p&gt;Wednesday, August 2nd, 2006 I asked Natalie Burke to marry me and she said yes… It was our 4 year anniversary (since we started dating) and I’m sure she’s been waiting awhile for me to ask, but I got her completely by surprise (it was awesome!!!)…&lt;/p&gt;
&lt;p&gt;…nuf said&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>I bought one</title>
    <link href="https://jonmagic.com/posts/i-bought-one/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/i-bought-one/</id>
    <content type="html">&lt;p&gt;Actually, my business bought one for me, but still… What am I talking about?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I bought a &lt;a href=&quot;http://www.apple.com/macbook/&quot;&gt;Macbook&lt;/a&gt; this afternoon!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ok, so I don’t have it yet (hopefully Monday) but I have been looking at Macbook pictures and have been reading about it as much as possible (including a firsthand report from xian)… So here are some links you can check out if you are interested…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.apple.com/macbook/&quot;&gt;Apple Macbook Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.flickr.com/photos/pealco/sets/72057594136649292/&quot;&gt;Flickr photo set of the black model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.appleinsider.com/article.php?id=1750&quot;&gt;Article about Apple’s design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gizmodo.com/gadgets/macbook/&quot;&gt;All of gizmodo’s coverage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.engadget.com/2006/05/16/apple-launches-macbook-13-inch-core-duo-black-and-white-cases/&quot;&gt;Engadget coverage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NEW!&lt;/strong&gt; &lt;a href=&quot;http://www.macworld.com/2006/05/firstlooks/macbookfirst/index.php&quot;&gt;review by Macworld, sweet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.engadget.com/2006/05/17/hands-on-with-the-apple-macbook/&quot;&gt;Engadget hands on at the Apple store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://store.apple.com/Catalog/US/Images/comparison_chart.html?siteID=lw9MynSeamY-YeeW149Vmk0SuMTYMKvCrw&quot;&gt;Macbook and Macbook Pro comparison chart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://arstechnica.com/staff/fatbits.ars/2006/5/16/4004&quot;&gt;FatBits glossy screen crap shoot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.forbes.com/markets/bonds/2006/05/16/apple-macbook-0516markets18.html&quot;&gt;Forbes financial review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.johnwaller.org/apple/macbook/&quot;&gt;John Waller’s hands on&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s all I’ve got so far, but hopefully tomorrow the reviews will start rolling in…&lt;/p&gt;
&lt;p&gt;p.s. I bought the black one&lt;/p&gt;
&lt;p&gt;Here is the latest I’ve found 😃&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.macworld.com/2006/05/firstlooks/macbookbench/index.php&quot;&gt;MacWorld benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.kodawarisan.com/macbook/macbook001.html&quot;&gt;Macbook taken apart, all the way&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://reviews.cnet.com/Apple_MacBook_13_inch_2_0GHz_Intel_Core_Duo/4505-3121_7-31884384-2.html?tag=nav&quot;&gt;Cnet Macbook video review&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve ordered 2gb of RAM and a 120gb SATA laptop hard drive, so come Monday my lappy will be upgraded and reinstalled and rocking!!!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://youtube.com/watch?v=8c6ckjy-gdY&quot; title=&quot;Video&quot;&gt;Easy Ram and HDD replacement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://arstechnica.com/reviews/hardware/macbook.ars/1&quot;&gt;Ars Technica review&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Hamachi all the way...</title>
    <link href="https://jonmagic.com/posts/hamachi-all-the-way/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/hamachi-all-the-way/</id>
    <content type="html">&lt;p&gt;Ok, I’ve been following the development of Hamachi, a.k.a. way too darn easy &lt;strong&gt;VPN&lt;/strong&gt; for a couple months now… Well I finally started using it today and I’ve got to say… &lt;strong&gt;WOW&lt;/strong&gt;, that was way too easy…&lt;/p&gt;
&lt;p&gt;But that’s the way we like it around here — things so easy that you don’t have to even think about them, they just work…&lt;/p&gt;
&lt;p&gt;Wondering what the heck I’m talking about yet? Here’s the deal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fact1 – &lt;strong&gt;VPN&lt;/strong&gt; stands for Virtual Private Network.&lt;/li&gt;
&lt;li&gt;Fact2 – What &lt;strong&gt;VPN&lt;/strong&gt; really means is, I can connect 2 or more computers together, no matter how far they are apart, and they’ll think that they are sitting right next to each other and talk their little computer language to their hearts’ content.
&lt;ul&gt;
&lt;li&gt;For example: I have a computer in Michigan and my friend has a computer in California and we want to share files with each other, share each other’s printer, share music, etc… But how can we do this securely without anyone eavesdropping and stealing our stuff? With a &lt;strong&gt;VPN&lt;/strong&gt; of course…&lt;/li&gt;
&lt;li&gt;Does it make sense yet?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Fact3 – &lt;strong&gt;VPN&lt;/strong&gt;’s have not been the easiest thing to configure for a number of years, and therefore were not used, or were used and cost a lot of money…&lt;/li&gt;
&lt;li&gt;Fact4 – Today that has changed…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you go to &lt;a href=&quot;http://hamachi.cc/&quot;&gt;Hamachi’s Website&lt;/a&gt; you can download Hamachi for Windows or Linux and install it and use it inside of 2 minutes. If you use an &lt;a href=&quot;http://www.apple.com/&quot;&gt;Apple Computer&lt;/a&gt; running &lt;strong&gt;OSX&lt;/strong&gt; then you’ll want to head over to this forum and check it out, or just continue reading as I’m going to give my own little How-To…&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First, go to &lt;a href=&quot;http://www-user.rhrk.uni-kl.de/~nissler/tuntap/&quot;&gt;This Website&lt;/a&gt; and download the tuntap that is appropriate for your version of &lt;strong&gt;OSX&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Second, once that file is downloaded open a Terminal session and browse to &lt;code&gt;~/Desktop&lt;/code&gt; (or wherever you just downloaded that file to).&lt;/li&gt;
&lt;li&gt;Type:
&lt;ul&gt;
&lt;li&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;tar&lt;/span&gt; zxvf tuntap*.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Now go to Finder and double click the “tuntap_installer.pkg” icon and follow the directions.&lt;/li&gt;
&lt;li&gt;Go to &lt;a href=&quot;http://files.hamachi.cc/osx&quot;&gt;This Website&lt;/a&gt; and download the latest version of Hamachi for &lt;strong&gt;OSX&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open the Terminal again and browse to wherever you downloaded the hamachi file to.&lt;/li&gt;
&lt;li&gt;Type:
&lt;ul&gt;
&lt;li&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;tar&lt;/span&gt; zxvf hamachi-0.9.9.9-12-osx.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Now in your terminal type:
&lt;ul&gt;
&lt;li&gt;
&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; tuncfg&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In Finder, find the hamachi file you just expanded, look in the new folder that was created.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;README&lt;/strong&gt; and follow the directions from there and you’ll be up and running in no time 😃&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  
  <entry>
    <title>Forever Remember Me</title>
    <link href="https://jonmagic.com/posts/forever-remember-me/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/forever-remember-me/</id>
    <content type="html">&lt;p&gt;So I’ve finished my first big programming project, &lt;a href=&quot;https://web.archive.org/web/2012/https://web.archive.org/web/2012/http://www.foreverrememberme.com&quot;&gt;Forever Remember Me&lt;/a&gt;, a website catering to the families and friends of those who have passed away… It is essentially a place for these families to create a memorial, and upload pictures, leave comments, and leave tributes (donations, which can go to a charity)… So, make sure and check it out…&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/2012/https://web.archive.org/web/2012/http://www.foreverrememberme.com&quot;&gt;https://web.archive.org/web/2012/http://www.foreverrememberme.com&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>flock, the good and the bad</title>
    <link href="https://jonmagic.com/posts/flock-the-good-and-the-bad/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/flock-the-good-and-the-bad/</id>
    <content type="html">&lt;p&gt;Well, I’ve got mixed feelings about &lt;a href=&quot;http://www.flock.com/&quot;&gt;flock&lt;/a&gt; right now. Despite the negatives I’m about to list, you should definitely try it out if you can…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Positives:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It just seems snappier on my 867mhz PowerBook than Firefox. I wonder if they’ve optimized it at all? Firefox’s speed has been the one thing that kept me from switching all my web browsing from Safari to Firefox, so maybe Flock will do the trick?&lt;/li&gt;
&lt;li&gt;It looks cool, clean low profile interface, no big ugly extras.&lt;/li&gt;
&lt;li&gt;It has great features: blog posting, &lt;a href=&quot;http://del.icio.us/&quot;&gt;del.icio.us&lt;/a&gt; favorites, &lt;a href=&quot;http://flickr.com/&quot;&gt;flickr&lt;/a&gt; bar, and it is based on Firefox, so who knows what extensions and themes will come out…&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Negatives:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Limited blog support, won’t work with my typo blog &lt;strong&gt;UPDATE&lt;/strong&gt; I got it working, just had to click “Cancel” after it fails to auto detect your blog, and then it lets you setup stuff manually… I’m posting this update via Flock.&lt;/li&gt;
&lt;li&gt;Creating a new favorite with tags does not tag it in &lt;a href=&quot;http://del.icio.us/&quot;&gt;del.icio.us&lt;/a&gt; (this has to be a bug that they haven’t fixed yet).&lt;/li&gt;
&lt;li&gt;There was way too much hype surrounding Flock. Thankfully I ignored most of it, so I’m not disappointed too much, but it still doesn’t quite live up to what I thought it would be… Thank goodness this is only a dev release I’m using 😃&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;
I think this is going to be a great browser, and there is a pretty good chance I will use it as my primary (hopefully only) web browser once it is a little more mature… actually, I’ll use it as my primary now, at least for a few days, and see if I can find any other nuggets hidden in there… nuf said.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Another Year</title>
    <link href="https://jonmagic.com/posts/another-year/"/>
    <updated>2006-09-30T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/another-year/</id>
    <content type="html">&lt;p&gt;My head hurts…&lt;/p&gt;
&lt;p&gt;I should be going to sleep right now, but I’m having such a hard time letting go… this has been a crazy week of late nights programming, long days at work, and crappy weather… but it has been a good week. I’ve learned a lot, spiritually and vocationally… I worked 12 hours today and accomplished a lot, even had lunch with a good friend and mentor. My coworker, Josh, and I have been getting along extremely well, which is exciting in and of itself. He had a pretty killer week but stayed on top of things and didn’t lose it (which is good, because I’ve been worrying about him)… So all in all, I’m pretty excited to be going into tomorrow—Friday, the last day of the week. I’ll be out of state from tomorrow morning until Saturday evening (weird, I’ll be 24 then).&lt;/p&gt;
&lt;p&gt;Another year gone past, the best year in a lot of years if you think about it… new beginnings, painful endings, learning, appreciating, worshipping, crying, calling, moving, working, wondering, loving, living, dying.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Time for change</title>
    <link href="https://jonmagic.com/posts/time-for-change/"/>
    <updated>2005-09-28T00:00:00Z</updated>
    <id>https://jonmagic.com/posts/time-for-change/</id>
    <content type="html">&lt;p&gt;I’ve been meaning to redo my site for quite some time now… &lt;a href=&quot;http://www.blosxom.com/&quot;&gt;blosxom&lt;/a&gt; was great, but with time come changes. So I’ve switched to using &lt;a href=&quot;http://typo.leetsoft.com/&quot;&gt;Typo&lt;/a&gt; for my blogging engine… It was built using &lt;a href=&quot;http://www.rubyonrails.com/&quot;&gt;RubyOnRails&lt;/a&gt;, a new web development framework that is pretty nifty…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What does this mean for you?&lt;/strong&gt; Not much really, a new look and feel…
My old site is still there with all the old content, just use the links on the right to access it… I considered importing all my old posts to the new system, but decided I don’t have enough time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What does this mean for me?&lt;/strong&gt; Again, not much. It’s going to be easier to post now, and I can enhance my site using quite a bit more as I have time… Any new feature I want I can implement, whether someone else has done it or not… Hopefully this will get me excited about blogging again, so you my poor reader(s) do not get bored 😃&lt;/p&gt;
&lt;p&gt;Don’t forget to change your newsreaders to point at the new &lt;a href=&quot;http://feeds.feedburner.com/jonmagic&quot;&gt;xml feed&lt;/a&gt;…&lt;/p&gt;
</content>
  </entry>
</feed>
